难点
不同请求响应头设置
大部分的请求头都是’Content-Type’:‘application/json’
但也有少数请求需要的是’multipart/form-data’,例如图片上传
这时候就要在request.js文件里面统一配置,在发送请求前判断属于哪一种请求,对’Content-Type’进行配置
// 添加请求拦截器
request.interceptors.request.use(function (config) {
// 在发送请求之前做些什么
Toast.loading({
msg: '请求中...',
forbidClick: true,
loadingType: 'spinner',
duration: 0
})
// console.log(config.url);
// 根据请求的不同设置不同的请求头
if(config.url.startsWith('/staff/window') || config.url.startsWith('/staff/dishIsshoucang') || config.url.startsWith('/staff/register') ){
config.headers['Content-Type'] = 'application/json'
}else if (config.url.startsWith('/user/upload') || config.url.startsWith('/post') || config.url.startsWith('/staff') ) {
config.headers['Content-Type'] = 'multipart/form-data'
} else {
config.headers['Content-Type'] = 'application/json'
}
return config
}
解决跨域问题
由于浏览器的同源策略,当本地服务器发请求到 后端服务器接口时,通常会发生跨域问题
跨域可以由后端人员解决,通常解决方式时配置cors
前端也可以解决跨域,我用的vue脚手架开发,所以要解决跨域,需要在vue.config.js中配置
代理,通过代理服务器发送请求
devServer: {
proxy: {
'/api': {// 匹配所有以 '/api'开头的请求路径
target: 'http://10.102.250.138:9090',
changeOrigin: true,
pathRewrite: {'^/api': ''},
ws:true,
}
},
},
切换餐厅
在菜单页面,每个餐厅展示的菜品不一样,点击餐厅后,要切换成相对应的菜品,
后端返回的数据是这样的,由于缺乏实战经验,怎么做出来这个功能思考了很长时间。
最终想到用index的方式解决,每个餐厅对应一个index,当点击当前餐厅时,activeindex就是当前的餐厅index,然后再根据index在data中取值,例如data[index].hotDishList
<ul>
<li v-for="(item, index) in list" :key="item.canteenWindowId">
<a :class="{ active: index === activeIndex }" @click="activeIndex = index" href="javascript:;">{{ item.canteenWindowName}}</a>
</li>
</ul>
//存在就渲染出来
<div v-for="item in list[activeIndex]?.hotDishList" :key="item.hotDishId" class="text">
头像的更改
个人头像的修改是最大的难点,这个功能花费了两三天,因为做出来的要不是有bug,要不就是达不到理想效果,因为我用了vant ui,里面有图片上传的组件
但是这种有问题,基础用法只能展示图片,不能进行修改
文件预览版的可以展示,也可以进行修改,但是修改框始终存在着,而且有时候无法显示用户原本的头像
经过对<van-uploader中参数的研究,经过反复测试,最终得出理想效果
<van-uploader v-model="fileList" multiple :max-count="1" :after-read="afterRead" />
//获取个人信息
getMyDate(){
getMyDate(this.userInfo.userId)
.then(res=>{
this.touImg=res.data.userAvatar
this.fileList.push({ url: this.touImg,isImage: true })
})
},
给van-uploader建立一个双向绑定 fileList,当获取到用户信息时候,把用户头像push到filelist中,由于uploader格式的限制,需要用这种方式进行push,this.fileList.push({ url: this.touImg,isImage: true })。
当用户修改时,只需要点击叉号,删除当前预览的照片,因为:max-count=“1”,只能上传一张照片,当照片消失时,上传按钮会出现,点击上传,就能完成照片的修改
changeTouxiang(this.userInfo.userId,file.file).then((res)=>{
// console.log(res);
})
亮点
组件复用
有时候,一个页面的大致结构相似,例如主页的所有贴子,搜索出来的贴子等等,进行组件复用提高开发效率
懒加载
路由懒加载 & 异步组件, 不会一上来就将所有的组件都加载,而是访问到对应的路由了,才加载解析这个路由对应的所有组件
将路由文件中的代码改成以下样式:
const ProDetail = () => import('@/views/prodetail')
const Pay = () => import('@/views/pay')
const MyOrder = () => import('@/views/myorder')
mixins复用
多个页面需要一个功能时,用mixins进行复用,使代码简洁,提高开发效率
1 新建一个 mixin 文件 mixins/loginConfirm.js
export default {
methods: {
// 是否需要弹登录确认框
// (1) 需要,返回 true,并直接弹出登录确认框
// (2) 不需要,返回 false
loginConfirm () {
if (!this.$store.getters.token) {
this.$dialog.confirm({
title: '温馨提示',
message: '此时需要先登录才能继续操作哦',
confirmButtonText: '去登陆',
cancelButtonText: '再逛逛'
})
.then(() => {
// 如果希望,跳转到登录 => 登录后能回跳回来,需要在跳转去携带参数 (当前的路径地址)
// this.$route.fullPath (会包含查询参数)
this.$router.replace({
path: '/login',
query: {
backUrl: this.$route.fullPath
}
//route.fullPath 包含从基本URL后开始的路径,假设基本URL(base URL)为 /app,并且当前路由为 /app/home?a=1,那么route.path的值将是 /home?a=1;
})
})
.catch(() => {})
return true
}
return false
}
}
}
2 页面中导入,混入方法
import loginConfirm from '@/mixins/loginConfirm'
export default {
name: 'ProDetail',
mixins: [loginConfirm],
...
}
用户交互体验
在首页和其他展示多个数据的页面,有时候下部的导航栏会挡住数据展示,影响用户使用,所以做了一个功能,当用户往下滑动时,底部导航栏隐藏
data(){
return {
isNavbarVisible: true // 导航栏的显示状态
};}
},
mounted() {
window.addEventListener('scroll', this.handleScroll);
},
beforeDestroy() {
window.removeEventListener('scroll', this.handleScroll);
},
methods: {
handleScroll() {
const threshold = 100; // 滚动多少距离后隐藏导航栏,根据实际情况调整
const scrollTop = window.scrollY;
this.isNavbarVisible = scrollTop < threshold;
}
}