1.install vue router
vue2.x对应vue router3.x版本
vue3.x对应vue router4.x版本
npm install vue-router@3.x / vue-router@4.x
2.router文件配置
1.导入VueRouter
2.将VueRouter绑定到Vue上
3.创建VueRouter实例并且传入参数配置项
4.创建router路由映射表
import Vue from 'vue';
import VueRouter from 'vue-router';
import Products from '../src/components/homeComponents/productsMy';
Vue.use(VueRouter);
const routes = [{
path: '/', //路由地址
name: 'landing', //给路由起个名字,传参的时候会用到
redirect: '/home' //路由重定向
},{
path:'/home',
name: 'home',
component: ()=>import('../src/components/homeMy.vue'), //异步加载该component
children: [{ //配置子路由
path: '/home/products',
name: 'home_products',
component: Products
}]
},
{
path:'/user',
name: 'user',
component: ()=>import('../src/components/userMy.vue')
},
{
path:'/list/:id', //动态路由匹配
name: 'list',
component: ()=>import('../src/components/listMy.vue')
},
{
path: '*', //剩余匹配,只能放在最后一项,当所有上面的路由没有被匹配到的时候,匹配到该路由
redirect: '/home'
}
]
const router = new VueRouter({
routes, //路由映射表
mode: 'hash' //路由模式hash or history
})
export default router;
3.组件配置及使用
1.需要给用到路由的组件在模版里面配置router-view标签,相当于指定这些组件是受路由管控的
2.在模版里面使用router-link配置to='字符串路由’或者v-bind:to="JS表达式"跳转到指定路由对应的页面
3.编程式导航,在JS代码里面通过this.$router.push(参数和上面to的值相同)
//params 传参
<template>
<div class="">home
<router-link to='/home/products'>to product</router-link>
<br>
<router-link :to="{ name:'list', params:{id:1,g:'e'} }">to list</router-link>
<router-view></router-view>
<button @click="f">to list2</button>
</div>
</template>
<script>
export default {
data() {
return {};
},
methods:{
f(){
setTimeout(()=>{
// 编程式导航 push的参数等同于to的参数
// push replace go back go(-1) === back
// push会新增历史记录, replace不会新增历史记录
this.$router.push('/list/3')
}, 1000)
}
}
}
</script>
// query传参
<template>
<div class="">
<h1>products</h1>
<ul>
<li>
<router-link :to="{name: 'user', query:{a:1, b:'vv'}}">子路由组件button</router-link>
</li>
</ul>
</div>
</template>
<script>
export default {
data () {
return {
}
},
}
</script>
<style scoped lang="scss"></style>
hash路由和history路由
1. hash路由利用的是hashchange事件
2. history路由利用的是popstate事件和两个方法 pushState和replaceState方法
路由传参的方式params和query
1. query传参会在url地址后面拼接参数
2. params传参是通过动态路由匹配
params传参刷新页面参数丢失问题:
如果在路由映射表里面配置则不会丢失,没配置会丢失
会丢失的参数还可以存储在vuex或者存在localStorage里面
4.修改选中路由的样式
a.第一种修改方式,修改全局的,不推荐使用
在router配置文件里面配置linkActiveClass(路由被当前激活路由包含)和linkExcatActiveClass(路由和当前激活路由完全精确匹配)
//在router实例文件
const router = new VueRouter({
routes,
mode: 'hash',
//不推荐在此处修改选中路由的样式,可以在模版页面使用active-class或者active-exact-class进行局部修改
// linkActiveClass: 'qqq', //修改全局的路由的样式,当路由包含的时候
// linkExactActiveClass: 'www' //修改全局的路由的样式,当路由完全匹配的时候
})
b.第二种修改方式,修改局部的
active-class 和exact-active-class
//在组件文件里面修改
<template>
<div>
<router-link :to="{path:'home'}">首页</router-link>
<router-link to="/user" active-class="www" exact-active-class="uuu">我的</router-link>
<router-link to="/user?q=1">我的3</router-link>
<router-link to="/home/qqq">qqq</router-link>
<router-view></router-view>
</div>
</template>
4.导航守卫
导航守卫有3种形式,全局守卫,路由守卫和组件守卫。
a.最常用的是全局前置守卫,在路由跳转之前做一些权限校验,满足权限则执行next方法到下一步,不满足权限则跳转到指定路由页面。
b.除了全局后置守卫,所有的导航守卫方法都接收3个参数(to, from, next),to和from相当于$route对象(包含path,match,params, query等信息),并且必须要执行next方法到下一步;全局后置守卫只接收两个参数(to, from)并且不会改变导航本身。
c.只有组件内前置守卫的next函数可以接受一个回调函数作为参数,并且组件实例本身被作为参数传递给回调函数
1.全局守卫
// 全局前置守卫
router.beforeEach((to, from, next )=>{
// to 和 from的格式类似于$route
// if(to.path === '/user') next();
// 必须调用next到下一步,next的参数等同于push的参数
if(!to.meta.role){
document.title = "test";
next();
return;
}
if(to.meta.role.includes(to.meta.title)) document.title = to.meta.title;
next();
// next('/user'); // 死循环,使用next进行路径跳转的时候也会触发前置守卫
})
//全局后置守卫
router.afterEach(()=>{
// console.log(to, from)
})
//全局解析守卫
router.beforeResolve,和beforeEach类似,区别是在导航确认之前,同时在所有组件内守卫和异步路由组件解析之后调用
2.路由守卫
路由守卫是配置在路由映射表里
beforeEnter: (to, from, next)=>{…}
{
path:'/list/:id',
name: 'list',
component: ()=>import('../src/components/listMy.vue'),
beforeEnter: (to, from, next)=>{ //路由配置守卫
// 与全局前置守卫的方法参数一致
// console.log(to, from, next)
next()
}
},
3.组件内路由守卫
beforeRouteEnter(to, from, next){…}
组件内进入守卫, 不能访问this, 因为守卫是在导航确认前被调用,因此新组件还没被创建,可以通过给next传一个回调函数来访问组件实例,在导航被确认的时候执行回调,并且把组件实例作为参数传递给该回掉函数
beforeRouteUpdate(to, from, next){…}
组件内更新守卫,当前路由改变,但是当前组件被复用时调用
beforeRouteLeave(to, from, next){…}
组件内离开守卫,导航离开该组件的对应路由时调用该守卫
//组件内进入守卫
beforeRouteEnter(to, from, next){
// 在渲染该组件的对应路由被confirm前调用
//不能访问组件实例this, 因为组件实例还没有被创建
// console.log(to, from)
next();
//next(vm => {console.log(vm)}) //vm为当前组件实例
},
//组件内更新守卫
beforeRouteUpdate(to, from ,next){
//当前路由改变,但是当前组件被复用时调用
//例如访问/foo/:id, 当路由在/foo/1 与 /foo/2之间切换的时候, 由于会渲染同样的Foo组件,所以组件会被复用
//可以访问组件实例
console.log('路由切换了,但是渲染的仍是同个组件')
next()
},
//组件内离开守卫
beforeRouteLeave(to, from, next){
//组件离开当前组件对应路由时触发, 或者获取到组件实例this
const res = confirm('确认离开吗?')
if(res){
console.log('确认离开')
next();
}else{
next(false);
}
}
导航实例调用方法addRoute
router.addRoute({path:‘…’, component:‘…’})
添加一条新路由规则, 可以接受两个参数,第一个参数可以指定父路由的name,第二个参数为新路由对应的路由映射对象,包含path, component等
let obj = { // 创建路由映射表在编译阶段将组件加载进来
'../src/components/homeComponents/qqqMy.vue': () => import('../src/components/homeComponents/qqqMy.vue')
}
let ary = [{
path: '/home/qqq',
componentURL: '../src/components/homeComponents/qqqMy.vue'
},
{
path: '/home/ttt',
componentURL: '../src/components/homeComponents/qqqMy.vue'
}]
ary.forEach(item =>{
router.addRoute('home', //当前路由的父路由的name, 如果该路由有name,并且名字与之相同,则会覆盖它
{
path: item.path,
component: obj[item.componentURL]
})
})
router.addRoute({
path: '*',
redirect: '/home'
})
$router 和 $route的区别
$router是vue router路由组件的实例对象,一般用来调用方法push, replace, go, back, addRoute
$route是路由参数对象
路由知识补充
路由组件与非路由组件的区别
1.路由组件一般放在pages/views文件夹下面,非路由组件一般放在components 文件夹下面
2.路由组件一般需要在router文件夹中注册(使用的即为组件的名字),非路由组件在使用的时候,是以标签的形式
3.在跟组件new Vue的时候往vue里面注册router,会使得组件里面可以访问到$router 和 $route
$route一般获取路由信息【path, params, query等】
r
o
u
t
e
r
一般进行编程式导航时进行路由跳转【
p
u
s
h
,
r
e
p
l
a
c
e
】
4.
注册完路由,不管路由组件还是非路由组件,身上都有
router一般进行编程式导航时进行路由跳转【push, replace】 4.注册完路由,不管路由组件还是非路由组件,身上都有
router一般进行编程式导航时进行路由跳转【push,replace】4.注册完路由,不管路由组件还是非路由组件,身上都有route和$router属性
路由的跳转
路由的跳转有两种方式
声明式导航router-link, 可以进行路由的跳转
编程式导航push/replace, 可以进行路由的跳转
编程式导航:声明式导航能做的,编程式导航都能做
但是编程式导航除了可以路由跳转,还可以做一些其他的业务逻辑
声明式导航:务必要有to属性