前言
关于自己使用vue+element写的一个系统中,配置动态路由遇到的问题总结
一、加载不出动态路由
未对接时我把所有的菜单路由都写在了静态路由。当对接时确实能根据不同的用户得到对应的菜单路由。但删除静态路由时,就加载不出页面,排查到的原因是因为处理动态菜单时,没有根据页面的正确url去懒加载vue组件;如:
route['component'] = resolve => require([`@/views/${url}`], resolve)
require加载的必须是对应的vue组件的全路径,这里的url是后端返回的变量,如果后端返回的url只是nameA,而我们的文件位置是views/parentA文件夹下的nameA.vue,就会一直加载不出该页面。
解决方法:
1.后端返回菜单数据的时候,返回一个上一级菜单parentA的名称:
route['component'] = resolve => require([`@/views/parentA/${url}`], resolve)
2.后端返回菜单数据的时候,返回的路径名url就是带有两级结构的菜单。如parentA/url:
route['component'] = resolve => require([`@/views/${url}`], resolve)
3.你也可以不需要parentA文件夹,即把parentA大模块里的小模块全部拆分出来,路径的上一级菜单就同名了。注意区分后端返回数据的大小写。(采取)
route['component'] = resolve => require([`@/views/${url}/${url}`], resolve)`在这里插入代码片`
二、页面刷新都是跳转到404页面
在设置动态路由的时候,如果在静态路由里面直接写了404页面。会导致刷新页面都是跳到404页面的问题。
原因:刷新后,都是先加载的静态路由,动态路由是在router.beforeEach路由守卫时判断并添加进去的。所以回先匹配到通配符*,怎么刷新都是404页面
解决:注释掉在静态路由里的404,把404页面push到动态路由后
三、刷新后对应菜单不高亮
这就涉及到elementUI的NavMenu 导航菜单的问题了, 属性default-active 是当前激活菜单的 index。官网文档举例:
可以看出,父组件的default-active和子组件index是一一对应的关系,两个相等才会触发高亮的效果。
注意:每个人对接的时候都要根据后端传回来的数据是什么格式去写代码,总之我们需要保证一点:点击菜单跳转页面的时候,这两个值都需要相等。
父组件:
<template>
<div class="maincontent">
<el-menu
ref="navmenu"
mode="horizontal"
background-color="#0e0e35"
text-color="#5c8e93"
active-text-color="#9af4eb"
style="width: 19.2rem; font-size: 0.25rem"
class="onetitle"
:class="collapse ? 'menu-bar-collapse-width' : 'menu-bar-width'"
:collapse="collapse"
:collapse-transition="false"
menu-trigger="click"
:unique-opened="true"
:default-active="activeIndex"
>
<!-- 导航菜单树组件,动态加载菜单 -->
<NavMenu v-for="item in navTree" :key="item.id" :menu="item"></NavMenu>
</el-menu>
<router-view></router-view>
</div>
</template>
<script>
import { mapState } from "vuex";
import NavMenu from "../../components/NavMenu.vue";
export default {
name: "MainContent",
components: {
NavMenu: NavMenu,
},
data() {
return {
test: "xx系统",
// activeIndex: "",
// 存起来的当前页面的path
urlPath: "",
};
},
computed: {
...mapState({
appName: (state) => state.app.appName,
themeColor: (state) => state.app.themeColor,
collapse: (state) => state.app.collapse,
navTree: (state) => state.menu.navTree, //菜单树
}),
// computed缓存中处理activeIndex=newStr,这个newStr需要和子组件里的index相等
activeIndex: {
get: function () {
// 如果打印出有菜单名
if (this.urlPath) {
const str = this.findUrl(this.navTree, this.urlPath) || "";
console.log("拼接的一级二级菜单id", str);
let newStr = str.slice(1);
console.log("newStr", newStr);
return newStr;
}
},
set: function () {},
},
},
mounted() {
var firstPath = this.$route.path.toString();
this.urlPath = firstPath.split("/")[1];
},
methods: {
// 遍历菜单树,拼接id
findUrl(data, url, str = "") {
for (let i = 0; i < data.length; i++) {
let item = data[i];
if (item.url == url) {
return str + "-" + item.id; } else {
if (item.children.length > 0) {
let hasStr = this.findUrl(item.children, url, str + "-" + item.id);
if (hasStr) {
return hasStr;
}
}
}
}
},
},
};
</script>
子组件:
<template>
<!-- 二级菜单及以上 -->
<el-submenu
v-if="menu.children && menu.children.length >= 1"
:index="'' + menu.id"
>
<template slot="title">
<i :class="menu.icon"></i>
<span slot="title" style="font-size: 0.24rem; margin-top: -0.4rem">{{
menu.menuName
}}</span>
</template>
<NavMenu
v-for="item in menu.children"
:key="item.id"
:menu="item"
></NavMenu>
<!-- <el-menu-item v-for="item in menu.children"
:key="item.id"
:menu="item"
@click="handleRoute(menu)">
<i :class="menu.icon"></i>
<span slot="title" style="font-size: 0.24rem">{{ menu.menuName }}</span>
</el-menu-item> -->
</el-submenu>
<!-- 一级菜单 -->
<el-menu-item v-else :index="'' + menu.parentId + '-' + '' + menu.id" @click="handleRoute(menu)">
<i :class="menu.icon"></i>
<span slot="title" style="font-size: 0.24rem">{{ menu.menuName }}</span>
</el-menu-item>
</template>
<script>
import { getIFrameUrl, getIFramePath } from "@/utils/iframe";
export default {
name: "NavMenu",
// 父组件传过来的
props: {
menu: {
type: Object,
required: true,
},
},
watch: {
menu: {
deep: true, //true为进行深度监听,false为不进行深度监听
handler(newVal) {
// console.log("改变", newVal);
},
},
},
methods: {
handleRoute(menu) {
//这里打印的active就是子组件的index,要与父组件的activeIndex相等
console.log('子组件打印了active','' + menu.parentId + '-' + '' + menu.id)
// 如果是嵌套页面,转换成iframe的path
let path = getIFramePath(menu.url);
if (!path) {
path = menu.url;
// console.log(path)
}
// 通过菜单URL跳转至指定路由
this.$router.push("/" + path);
},
},
};
</script>