$router 路由的集合
借鉴文章:
动态路由的使用
-
路由对象属性
- $route.path:当前路由的路径,总是解析为绝对路径,如 /foo/bar (string)
- $route.params:key/value 对象,包含动态片段和全匹配片段,没有则为{}
- $route.query:key/value 对象,表示 URl 参数,例如:/foo?user=1 即 route.query.user==1
- $route.hash:当前路由的 hash 值(带#),没有则为空字符串
- $route.fullPath:完成解析后的 URl,包含查询参数 hash 的完整路径
- $route.matched:Array,包含当前路由的所有嵌套的路由记录,其中包含 mate: 元信息的集合
- $route.name:当前路由的名称
- $route.redirectedFrom:如果存在重定向,即为重定向来源的路由的名字 -
路由跳转
2.1 声明式导航<router-link :to="页面路径"></router-link>
eg:
```js
// 没有传参时的跳转
<router-link :to="/index">测试页面</router-link>
// 传递参数, 和url拼接参数时一样都是拼接参数在后面
<router-link :to="/index?id=23">测试页面</router-link>
//跳转后页面获取参数
this.$route.params.id
```
2.2. vue-router里面的配置
```js
{
path: '/Descr/:id',
name: 'Descr',
component: Descr
}
// 跳转时页面
var id = 1;
this.$router.push('/Descr/' + id)
//跳转后页面获取参数
this.$route.params.id
```
2.3. 通过query属性传值(url中不显示参数)
```js
//跳转时页面
this.$router.push({
path: '/Descr',
query: {
name: '李四',
id: 3,
}
})
//跳转后页面获取参数对象
this.$route.query
```
2.4. 通过params属性传值(url中显示参数)
```js
//跳转时页面
this.$router.push({
name: '/Descr',
params: {
name: '李四',
id: 1,
}
})
//跳转后页面获取参数对象
this.$route.params
///父路由组件上使用router-link进行路由导航,传参用<router-link to="/one/login/001">的形式向子路由组件传递参数。使用router-view进行子路由页面内容渲染
```
总结:
1. 动态路由和query属性传值 页面刷新参数不会丢失, params会丢失
2. 动态路由一般用来传一个参数时居多(如详情页的id), query、params可以传递一个也可以传递多个参数
注意:**如果在Vue项目中传递的参数是一整个对象可以使用JSON.stringify将参数转换一下**
```js
// 跳转路由传递对象参数
var arr=JSON.stringify(this.对象)
this.$router.push('/Descr'+encodeURIComponent(arr))
```
>接收参数的时候,先用decodeURIComponent()将传递过来的参数转换一下,然后再用JSON.parse再次转换,这样,一个对象就完整的传递过来了,
```js
// 获取传过来的参数
var list = decodeURIComponent(this.$route.params.obj);
this.对象 = JSON.parse(list);
```
注意:**文件流数据file不能使用这个方法,因为file数据一用JSON来转换,就为空了,所以也不能用本地存贮,但可以使用vuex来保存**
- 路由的渲染
可以通过 标签去渲染
- hash 路由和 history 路由的区别
一般默认的vue路由就是hash模式,hash模式的路由:地址栏里面的url会带有#形式的,如果想要切换成history模式时,可以在
router
里的index.js
里面,创建路由实例时给修改了
const router = new VueRouter({
// 更改为history模式
mode:'history'
})
顶部面包屑的编写
- 编写面包屑组件
- 借鉴使用 elment ui 组件的面包屑
- 面包屑组件路径:src/components/BreadCrumbs/index.vue
- 动态路由编写
记录动态路由遇到的坑
关于 router 动态添加路由和菜单所遇到的坑和解决方法,记录以防止下次遇到
- 在 store 里面对获取的路由信息进行处理
import layout from "@/views/layout";
const menu = {
//初始对象(和data类似)--放置要用到的值
state: {
routers: [],
addRoutes: [],
},
//将值赋予给state
mutations: {
//获取路由信息
SET_ROUTERS: (state, routers) => {
state.routers = routers;
},
//获取拼装好的路由路径
SET_ADD_ROUTERS: (state, addRoutes) => {
state.addRoutes = addRoutes;
},
},
//异步回调事件,操作mutations里的事件赋值给state
actions: {
//获取路由信息
getRouters({ commit }, menuData) {
commit("SET_ROUTERS", menuData.data);
let menu = filterChildren(menuData.data);
//添加路由
commit("SET_ADD_ROUTERS", menu);
//左侧菜单路由
commit("SET_SIDEBAR_ROUTERS", menu);
},
},
};
//拼接路由
function filterChildren(router) {
//循环遍历拼接路由
return router.filter((route) => {
//判断是否含有下级路由
if (route.children && route.children.length > 0) {
route.component = layout;
//再次循环
route.children = filterChildren(route.children);
} else {
route.component = loadView(route.component);
}
return true;
});
}
// 路由路径拼接
function loadView(view) {
// 路由懒加载
return () => import(`@/views/${view}`);
}
export default menu;
-
创建 permission.js 在根目录下,在 main.js 里面引用
import NProgress from "nprogress"; import store from "./store"; import router from "./router"; const NoLoginList = ["/iframe"]; //免登录页面 import menuData from "@/assets/model/menuData.json"; router.beforeEach(async (to, from, next) => { // to 路由当前路径,可以获取当前路由的信息 // from 要离开去的路由页面,可以获取当前路由的信息 // next 放过拦截,执行下一个页面跳转 // 得到本地存储的token 想要进其他页面,就要带token let token = store.state.user.token; if (token) { //有登录并在登录页,直接进入首页 if (to.path === "/login") { next("/"); } else { //非登录页直接放过 //判断是否是初次进入渲染动态路由,当跳转其他路由时不要再次添加和获取 //模拟后台请求数据 await store.dispatch("getRouters", menuData); router.addRoutes(store.state.menu.addRoutes); // 这一行就是解决问题的最终办法, 重新进当前路由 next(); } } else { //未登录,如果是免登录页面直接进入 if (NoLoginList.indexOf(to.path) !== -1) { // 获取重定向页面路径 next(); } else if (to.path === "/login") { //多加一步判断是否是去登录,以免进入路由死循环里 next(); } else { //非登录页,也不是免登录页就跳转到登录页 next({ path: "/login", query: { redirect: to.fullPath } }); } } });
- 错误信息
[vue-router] router.addRoutes() is deprecated and has been removed in Vue Router 4. Use router.addRoute() instead.
原因:addRoutes()已弃用,并且已在 Vue 路由器 4 中删除。
解决:改为 addRoute()就可以了 -
记录报错内容
- 使用 router.addRoute()
router.beforeEach(async (to, from, next) => {
//其他代码省略
router.addRoute(store.state.menu.addRoutes);
//其他代码省略
});
- 运行报错信息
错误:[vue路由器]“路径”在路由配置中是必需的
Uncaught (in promise) Error: [vue-router] “path” is required in a route configuration.
原因:添加一条新的路由规则记录作为现有路由的子路由。不能直接添加数据类型的路由信息,需要一条一条的添加
如果该路由规则有 name,并且已经存在一个与之相同的名字,则会覆盖它
解决:一条一条添加就行 2. 使用 router.addRoute()
解决代码
router.beforeEach(async (to, from, next) => {
//其他代码省略
store.state.menu.addRoutes.forEach((item) => {
router.addRoute(item);
});
next();
//其他代码省略
});
-
运行报错信息:页面出现空白
在路由的前置守卫里面, 使用 addRoutes 钩子后, 直接调用 next()
如果当前页面的 路由 是通过 addRoutes 添加进去的 刷新页面就会出现
对应的路由组件不会渲染的情况, 也不会报错,页面会显示为空白
详细原因未知: 大致理解为, 当进入路由的前置钩子 (router.beforEach) 的时候,
路由的结构是不会发生变化的, 至少本次跳转, 路由的结构是不会变化的
也就是相当于我们举报一次活动,明天能看,但我们今天就要看一样,所以也就不能使用了 3. 使用 next({…to, replace: true})解决页面空白问题router.beforeEach(async (to, from, next) => { //其他代码省略 store.state.menu.addRoutes.forEach((item) => { router.addRoute(item); }); // 这一行就是解决空白问题的最终办法, 重新进当前路由 next({ ...to, replace: true }); //其他代码省略 });
运行报错信息:加入这行代码会造成页面陷入死循环,每次都去添加,重进当前路由,
解决方法:只使用一次:在初次加载时添加路由,其他页面路由跳转不在添加 4. 加入 isAddRouter 判断是否是初次加载动态路由let isAddRouter = false; router.beforeEach(async (to, from, next) => { //其他代码省略 //判断是否是初次进入渲染动态路由,当跳转其他路由时不要再次添加和获取 if (!isAddRouter) { store.state.menu.addRoutes.forEach((item) => { router.addRoute(item); }); // 这一行就是解决空白问题的最终办法, 重新进当前路由 next({ ...to, replace: true }); } else { next(); } //其他代码省略 });
- 最终 permission.js 代码
//当导航触发时,前置路由守卫会创建顺序,异步解析执行获取路由信息
import NProgress from "nprogress";
import store from "./store";
import router from "./router";
const NoLoginList = ["/iframe"]; //免登录页面
import menuData from "@/assets/model/menuData.json";
let isAddRouter = false;
router.beforeEach(async (to, from, next) => {
// to 路由当前路径,可以获取当前路由的信息
// from 要离开去的路由页面,可以获取当前路由的信息
// next 放过拦截,执行下一个页面跳转
// 得到本地存储的token 想要进其他页面,就要带token
NProgress.start();
let token = store.state.user.token;
if (token) {
//有登录并在登录页,直接进入首页
if (to.path === "/login") {
next("/");
} else {
//非登录页直接放过
//判断是否是初次进入渲染动态路由,当跳转其他路由时不要再次添加和获取
if (!isAddRouter) {
//模拟后台请求数据
await store.dispatch("getRouters", menuData);
//渲染之后改变状态,截止动态路由的再次渲染
isAddRouter = true;
// router.options.routes里的数据需要手动添加,
// router.addroutes/router.addroute添加的数据是不会自动到这里面的
router.options.routes = [...store.state.menu.addRoutes];
store.state.menu.addRoutes.forEach((item) => {
router.addRoute(item);
});
// 这一行就是解决问题的最终办法, 重新进当前路由
next({ ...to, replace: true });
} else {
next();
}
}
NProgress.done();
} else {
//未登录,如果是免登录页面直接进入
if (NoLoginList.indexOf(to.path) !== -1) {
// 获取重定向页面路径
next();
} else if (to.path === "/login") {
//多加一步判断是否是去登录,以免进入路由死循环里
next();
} else {
//非登录页,也不是免登录页就跳转到登录页
next({ path: "/login", query: { redirect: to.fullPath } });
}
NProgress.done();
}
});
解决 vue 路由跳转未匹配路径时出现空白页的问题
借鉴文章:
当一个导航触发时,全局前置守卫按照创建顺序调用。守卫是异步解析执行,此时导航在所有守卫 resolve 完之前一直处于 等待中。
每个守卫方法接收三个参数:
to: Route: 即将要进入的目标 路由对象
from: Route: 当前导航正要离开的路由
next: Function: 一定要调用该方法来 resolve 这个钩子。执行效果依赖 next 方法的调用参数。
next(): 进行管道中的下一个钩子。如果全部钩子执行完了,则导航的状态就是 confirmed (确认的)。
next(false): 中断当前的导航。如果浏览器的 URL 改变了 (可能是用户手动或者浏览器后退按钮),那么 URL 地址会重置到 from 路由对应的地址。
next(‘/’) 或者 next({ path: ‘/’ }): 跳转到一个不同的地址。当前的导航被中断,然后进行一个新的导航。你可以向 next 传递任意位置对象,且允许设置诸如 replace: true、name: ‘home’ 之类的选项以及任何用在 router-link 的 to prop 或 router.push 中的选项。
next(error): (2.4.0+) 如果传入 next 的参数是一个 Error 实例,则导航会被终止且该错误会被传递给 router.onError() 注册过的回调。
确保要调用 next 方法,否则钩子就不会被 resolved。
- 在前置路由内配置,匹配路由
router.beforeEach(async (to, from, next) => {
/*
初次进入页面后,渲染动态路由后,重定向页面,会再走一边前置路由
在这一步处理未匹配相应用路由避免出现空白页面的问题
*/
//判断是否匹配到路由
if (to.matched.length === 0) {
//第一种情况: 404页面内容可以自定义 from.path ? next({ path: from.path }) : next({ path: "/404", redirect: "/404", hidden: true })
//第二种情况: 未自定义页面直接跳转到首页 from.path ? next({ path: from.path }) : next("/")
from.path ? next({ path: from.path }) : next("/");
} else {
next(); //有匹配到页面,跳转正确页面
}
}