一、动态菜单
1、问题:点击菜单,其他菜单都会打开,且选中某个菜单,其他菜单都会选中
(1)原因:菜单的属性index设置的问题(动态菜单中的path值是变量,所以要在index前面加上:),index是用来区分选中的菜单栏是哪个以及动态路由跳转的标识,index的值是唯一的
(2)解决方法:围绕index检查,检查index是否加:
2、问题:home页面代码内动态菜单数据获取的位置
(1)解决方法:在menu组件内的运用computed计算属性从 store里面获取;只需要获取这个值渲染到页面,不需要监听这个值的变化
二、动态路由
1、问题:刷新home页面后,页面报错,找不到对应的路由路径
(1)原因:动态路由的添加是异步操作,在异步操作还没有完成的时候,页面就加载完了,所以找不到动态路由的路径
(2)解决方法
每一次刷新页面,页面显示App.vue这个文件,所以在此文件的created函数中再次调用动态路由的添加,确保动态路由添加好后在跳转home页面
2、问题:登录跳转到home页面后,会显示未找到动态路由路径
(1)原因:登录跳转后,动态路由添加的异步操作还没完成,因此会找不到路径
(2)解决方法:将动态路由的添加放在存储菜单栏信息的actions里面执行,actions能执行异步任务,同时用promise封装,并返回,这样可以用.then的方法确保动态路由添加好后在跳转(下面代码含有动态路由的映射和添加的方法)
store内menu.js文件
import { RequestMenu} from "@/api/index.js";
import router from '@/router'
const viteComponent = import.meta.glob('@/views/**/*.vue')
const menu ={
namespaced:true,//命令空间
state:{
menu:{}
},
mutations:{
MENU(state,menu){
state.menu=menu
},
RemoveMENU(state){
state.menu={}
}
},
//actions可进行异步操作
actions:{
saveMenu({commit},role_id){
return new Promise(async(resolve,reject)=>{
//向后端请求菜单栏数据
let res= await RequestMenu(role_id)
let menu=res.sysmenu
//保存菜单栏
commit('MENU',menu)
// 格式化映射菜单数据为路由数据
let menuRouesList = formateMenuList(menu)
// 添加动态路由
menuRouesList.forEach(route => router.addRoute(route))
resolve()
}
)
},
removeMenu({commit}){
commit('RemoveMENU')
}
},
getters:{
menu:state=>state.menu
}
}
/**
* 添加动态路由
* 路由菜单接口数据映射成路由格式数据
*/
function formateMenuList(menuRoutes) {
let newMenuRoutes = []
menuRoutes.forEach(route => {
// 如果有子路由,递归调用函数本身,继续映射
let children
if (route.children && route.children instanceof Array) {
children = formateMenuList(route.children)
}
const { path, label, meta, iconCls, hidden } = route
let newRoute = {
path,
label,
meta,
iconCls,
hidden,
children,
}
// 组件映射
if (route.path.indexOf('/main') !== -1) {
newRoute = {
...newRoute,
component: () => import('@/views/home.vue'),
}
} else {
newRoute = {
...newRoute,
// component: () => Promise.resolve(require(`@/views/platform${route.path}`).default), //webpack router4版本
component: viteComponent[`/src/views/platform${route.path}.vue`], // vite router4
}
}
newMenuRoutes.push(newRoute)
})
return newMenuRoutes
}
export default menu
login页面
3、问题:关闭浏览器后,输入登录页面url,会直接跳转到home页面
(1)原因:在app.vue文件中,created函数中定义了若有角色id,则重新存储菜单栏,并跳转到home页面,角色id是存储在localStorage里面的,所以关闭浏览器不会消失,因此刷新页面或者关闭浏览器在进入会直接跳转到home页面
(2)解决方法
登录页面中,用sessionStorage存储角色id
三、商品列表
1、问题:商品列表下面的分页器点击如何实现不同的商品条数和当前页的商品显示的信息
** ** (1)解决方法:运用elementUI组件库里面的分页器,其中size-change、current-change事件用来调整页面显示的商品条数和当前商品信息
重点:因为要改变条数和当前页数,所以pageSize,pageNo定义在data数据里面,这样改变这两个值,就可以改变后端请求时传的参数值
四、登录身份认证(前置导航守卫)
1、使用场景:通过登录时存储在本地的token来判断是否用户已经登录,如果未检测到,则访问其他页面时,直接跳转到登录页面
2、使用方法:将定义的permission.js文件引入到main.js文件内
代码内容如下:
import router from './router/index'
import Cookies from 'js-cookie'
/**
* 全局前置导航守卫
* to: 目标路由
* from: 开始路由
* 返回值
* false 中断路由 true 继承路由
* return {path:'/product/list'}
* return {name:'nab'}
*/
router.beforeEach((to, from) => {
// 直接放行的路由 如:登录
if(to.name == 'login'){
return true
}
//如果没有登录不允许路由到主界面home
// 统一登录身份认证, 在没有登录的情况不允许进入需要登录身份认证的页面
// 具体实现方式: 登录成功后,保存token, 在全局前置导航守卫处统一判断
let token = Cookies.get('token')
if(token){
return true // 放行
}else{
return {path:'/'} //重定向到/路由登录界面
}
//解决刷新找不到菜单路径的问题
})
五、动态图表思路
1、安装echarts插件
https://echarts.apache.org/zh/index.html
(1)npm安装或者下载.js文件(放在public文件夹下)
2、template中定义模板,motheds中定义图表代码以及获取后端数据
3、mounted中使用methods中定义的方法
六、面包屑实现思路
1、面包屑实现场景
2、实现思路
(1)通过watch监听激活的route变化,用数组map方法获取route对象自带的matched中数组的meta.name值,将获取的数组付给data中定义的变量
(2)template模板中循环该数组从而显示数组内的内容
七、excel导出
1、安装
2、放入.js文件
3、将引入对应的模块
4、使用的代码
八、商品添加思路
1、商品分类选择的实现
(1)向后端请求商品分类数据,并赋值给data里面存储的变量
(2)模板里面的option选项循环遍历分类数据,其中value的属性是分类id,点击的时候存储的是这个分类id
<el-form-item label="商品分类" prop="categoryId">
<el-select v-model="shopForm.categoryId" placeholder="请选择商品分类">
<el-option
v-for="item in CategoryList"
:key="item.id"
:label="item.name"
:value="item.id"
/>
</el-select>
</el-form-item>
2、上下架选项最初显示上架的实现
在data里面对应的数据绑定中,值写1
模板中,label是关键,这样才能传1或0给后端
<el-form-item label="是否上架" prop="putaway">
<el-radio-group v-model="shopForm.putaway">
<el-radio label="1">上架</el-radio>
<el-radio label="0">下架</el-radio>
</el-radio-group>
</el-form-item>
3、商品图片上传的实现
(1)模板中的写法
<el-form-item label="图片" prop="picture">
<el-upload
:action="uploadUrl"
:show-file-list="false"
:auto-upload="true"
name="headerImg"
list-type="picture-card"
:before-upload="beforeAvatarUpload"
:on-change="getImgUrl"
class="avatar-uploader"
:on-success="handleAvatarSuccess"
>
<img v-if="imageUrl" :src="imageUrl" class="avatar" />
<el-icon v-else><Plus /></el-icon>
</el-upload>
</el-form-item>
(2):auto-upload="true" 是判断图片是否自动上传
:show-file-list="false"是判断是否可以多张图片上传
:action="uploadUrl"是自动上传给后端的url是多少
:before-upload="beforeAvatarUpload" 是图片上传之前进行图片的大小、类型的判定,如果没通过,则不会上传成功
:on-change="getImgUrl" 只要图片一变动就会触发,主要是获取图片转换的地址,然后赋给imgUrl用于能再页面看到上传的这张图片
:on-success="handleAvatarSuccess" 图片上传到后端成功后,需要执行相关方法:通过response这个参数,将后端返回的图片地址赋给存储商品信息地址的变量
重点注意:如果商品添加成功后,商品列表没有显示该图片,很有可能是再商品添加时,后端返回的图片上传地址没有拼接后端url,导致访问不到
(3)相关js代码
import { baseURL } from "@/utils/request";
data(){
return{
imageUrl: "",
uploadUrl: baseURL + "/api/uploadFile",
}
}
//图片上传之前进行类型和大小验证
beforeAvatarUpload(rawFile) {
//判断图片类型
let picArr = ["image/jpeg", "image/png"];
if (picArr.indexOf(rawFile.type) == -1) {
ElMessage.error("图片类型必须是jpeg或者png!");
return false;
} else if (rawFile.size / 1024 / 1024 > 2) {
ElMessage.error("图片大小不能超过 2MB!");
return false;
//判断图片大小
}
return true;
},
//图片文件状态改变时,获取图片地址用于显示图片
getImgUrl(rawFile) {
//展示上传图片的方法
this.imageUrl = URL.createObjectURL(rawFile.raw);
},
//图片上传成功的回调
handleAvatarSuccess(response) {
//获取后端响应的图片地址
this.shopForm.picture = baseURL + response.resultInfo.url;
},
九、角色管理-角色绑定菜单数据
1、使用Drawer抽屉组件和树形控件实现
2、Drawer抽屉组件
3、树形控件组件
(1)树形控件-获取菜单数据
(2)获取角色菜单数据(父传子将角色id传入树形控件中)
注意:因为获取角色菜单数据和总的菜单数据都是异步任务,但是获取角色菜单数据会比总的菜单数据先执行,因此通过promise封装获取总的菜单数据的代码,在.then的方法里面执行获取角色菜单数据,这样避免菜单节点没被选中的问题
(3)修改角色菜单数据
(4)注意:因为树形控件-菜单子组件关闭后,再次进入不会重新加载这个组件,因此需要通过v-if添加和删除菜单子组件,才会重新加载获取最新的后端数据
十、登录页面(其他页面)响应式
1、功能场景:窗口大小变化,左宽右窄布局变为左右对半,随着窗口变小,左右布局变为上下布局
2、 实现方式:使用element-UI组件库内的layout布局有个响应式布局来
十一、登录页面账号密码输入错误,登录状态失效和全局提示错误响应信息效果
1、场景效果:
2、实现方式:
(1)登录状态失效:使用.catch()方法捕获错误响应,在回调函数内将loading状态变为false;向后台发送登录请求时,用.then和.catch方法处理响应内容
(2)全局提示错误响应信息:在响应拦截器里面,设置错误提示信息
十二:全局loading进度条实现方法
1、场景:页面跳转时候出现加载状态
2、实现方式:nprogress插件+全局前置、后置守卫导航
(1)安装插件: npm i nprogress -S
(2)main.ts文件内引入css文件
(3)utils.js文件内封装开启加载和关闭加载的代码
(4)全局前置导航内开启加载动画,后置守卫导航关闭加载动画
十三、动态页面标题实现
1、场景:随着点击的菜单不同,页面标题显示对应的菜单名
2、实现方式:路由内定义meta字段,在全局后置守卫导航内获取到meta信息,然后赋值给document.title
版权归原作者 jr2319 所有, 如有侵权,请联系我们删除。