路由router/index.js
// 1 引入vue和vue-router
import Vue from 'vue';
import VueRouter from 'vue-router';
// 2 通过 Vue.use() 明确地安装路由功能
Vue.use(VueRouter);
/*
* 3 定义一些路由(即一个对象代表一个路由,都存放在数组routes中,也可以由外部导入)
* 每个路由都需要映射一个组件(即一个path对应一个component)
* 其他配置项包括name redirect meta等等
*/
const routes = [
{
// 会拼接到地址栏, 名字是自定义的('/'代表页面默认打开时的路由)
path: '/',
// 路由重定向(即只要到该路由就会被重定向到某路由,此处为'/home',所以此处无需映射组件)
redirect: '/home'
},
{
// 路由路径(当地址栏显示/home时,app.vue中的router-view便显示Home.vue的内容)
path: '/home',
// 路由名称(路由跳转时可以通过path,也可以通过name)
name: 'home',
// 组件懒加载(即处于此路由时才会导入该组件,而不是一开始就导入组件,利于性能优化)
// 也可以由其他文件直接导入
component: () => import('../views/Home.vue'),
// 默认显示子路由one
redirect: '/home/one',
// 路由的子路由(子路由的出口即router-view是需要写在其父级路由中的)
children:[
// 写法1,不加'/', 即代表'/home/list'
{path: 'one', component: () => import('../views/One.vue')},
// 写法2,加'/', 就需要写完整路由,也代表'/home/list'
{path: '/home/two', component: () => import('../views/Two.vue')}
],
// 路由源信息(按需使用)
meta: {
title: '主页',// 标题
icon: 'el-icon-s-home',// 图标
roles: ['admin', 'editor'],// 路由权限时使用
keepAlive: true,// 组件缓存时使用
}
}
];
// 4 创建路由实例
const router = new VueRouter({
// history模式地址栏不会显示#号,hash模式会显示#号,默认值是hash
mode: 'history',
routes
});
// 解决重复点击同一个路由时,控制台出现报错问题
// 报错内容:Uncaught (in promise) NavigationDuplicated: Avoided redundant navigation
const VueRouterPush = VueRouter.prototype.push
VueRouter.prototype.push = function push (to) {
return VueRouterPush.call(this, to).catch(err => err)
}
VueRouter.prototype.replace = function replace (to) {
return VueRouterPush.call(this, to).catch(err => err)
}
// 5 导出路由实例
export default router
一级路由的出口一般在app.vue中
二级及以上路由的出口,一般是在其父级路由相对应的组件内部
我是home页面
路由的跳转方式有两种,一种是声明式,一种是编程式(常用)
1、声明式路由(通过html标签跳转)
必传参数
one
two
其他参数
one
2、编程式路由(通过js跳转)
常用的跳转方式
// 封装一个函数,通过事件调用即可
methods: {
goOne() {
// 1、push (跳转到指定的url,在history中添加记录)
// this.$router.push('/home/one')
// this.$router.push({ path: '/home/one' })
// this.$router.push({ path: '/home/one', query: { a: 1 } })
// this.$router.push({ name: 'HomeOne' })
// this.$router.push({ name: 'HomeOne', params: { a: 1 } })
// 2、replace重定向(跳转到指定的url,不在history中添加记录)
this.$router.replace('/home/one');// 推荐写法
// this.$router.replace({ path: '/home/one' })
// this.$router.replace({ path: '/home/one', query: { a: 1 } })
// this.$router.replace({ name: 'HomeOne' })
// this.$router.replace({ name: 'HomeOne', params: { a: 1 } })
}
}
其他跳转方式
this.$router.forward(); // 前进
this.$router.back(); // 后退
this.$router.go(); // 向前或向后跳转n个页面(n/-n)
具体的写法在上面路由跳转时已说明,此处主要说明params和query的区别以及如果接收参数
1、参数接收
this.$route.params.id
this.$route.query.id
2、query和params的区别
1、搭配方式不同:query通常搭配path使用、params通常搭配name使用;
2、地址栏是否显示:query地址栏显示参数,params,地址栏不显示参数;
3、刷新是否造成数据丢失:query传值页面刷新也存在,params一刷新就没了(解决方案:在配置路由时加入占位符)
在path配置一个字段“:name”,它表示此字段是动态的。此时不管是路径'/home/two/Tom',还是'/home/two/John’,或者是其他的,都会跳转到此路由。
router/index.js
{
path: '/home/two/:name',
component: () => import('../views/Two.vue')
},
跳转
const name = 'xxx'; // name是动态变化的
this.$router.replace('/home/one/'+name);
1、全局导航守卫
router/index.js
// 全局导航守卫(即在路由跳转前后做一些事情)
// 1.全局前置守卫
router.beforeEach((to, from, next) => {
// 1.1 判断是否需要登录
if (to.meta.requireAuth) {
// 1.1.1 判断是否登录
if (store.state.token) {
next();
} else {
// 1.1.2 未登录则跳转到登录页面
next({
path: '/login',
// 1.1.3 将跳转的路由path作为参数,登录成功后跳转到该路由
query: {redirect: to.fullPath}
})
}
} else {
next();
}
// 1.2 判断是否需要权限
if (to.meta.roles) {
// 1.2.1 判断是否有权限
if (store.state.roles.some(role => to.meta.roles.includes(role))) {
next();
} else {
// 1.2.2 无权限则跳转到401页面
next({
path: '/401',
// 1.2.3 将跳转的路由path作为参数,登录成功后跳转到该路由
query: {redirect: to.fullPath}
})
}
} else {
next();
}
});
// 2.全局后置守卫(后置守卫没有next参数)
router.afterEach((to, from) => {
// 2.1 设置标题
document.title = to.meta.title;
// 2.2 设置面包屑
store.commit('setBreadcrumb', to);
});
2、路由独享守卫
路由独享守卫,在进入该路由前执行的函数,可以用来判断是否有权限进入该路由,如果没有权限则跳转到其他路由。
{
path: '/home',
component: () => import('../views/Home.vue'),
beforeEnter: (to, from, next) => {
next();
}
},
3、组件内导航守卫
组件内导航守卫,只在当前组件生效,父子组件互不影响
export default {
name: 'Home',
// 导航守卫
beforeRouteEnter(to, from, next) {
console.log('beforeRouteEnter')
next()
},
beforeRouteUpdate(to, from, next) {
console.log('beforeRouteUpdate')
next()
},
beforeRouteLeave(to, from, next) {
console.log('beforeRouteLeave')
next()
},
methods: {
}
};