一、安装
- 命令行进入项目的根目录, 执行
npm install vue-router --save
安装成功后, 在项目的package.json文件中的 dependencies 中会新增有 vue-router 这一项。
*注:这里可能会一个坑,出现版本问题,报出异常:
warning in ./node_modules/vue-router/dist/vue-router.esm-bundler.js "export ‘watchEffect’ was not found in 'vue’;
原因是默认下载的是最新版,支持vue3,而我用的是vue2。
我的解决方法是,卸载vue-router重新安装固定版本:
npm install vue-router@3.2.0
二、使用
vue-router 使用步骤:
- 在main.js中引入
import VueRouter from 'vue-router'
; - 安装插件
Vue.use(VueRouter)
; - 创建路由对象并配置路由规则
let router = new VueRouter({routes:[{path:'/home',component:Home}]})
; - 将路由对象传递给Vue的实例,options中加入 router:router
- 在页面模板中使用
<router-view></router-view>
留坑
具体代码实现如下:
import Vue from 'vue'
import App from './App.vue'
// 引入 vue-router 插件
import vueRouter from 'vue-router'
// 安装插件
Vue.use(vueRouter);
// 导入组件
import Home from '@/views/home'
//创建路由对象,配置路由规则
let router = new vueRouter({
routes: [
{
path: '/home',
name: 'Home',
component: Home
},
{
path: '/about',
name: 'About',
component: () => import('@/views/about')
}
]
})
Vue.config.productionTip = false
new Vue({
// 将路由对象传递给Vue的实例
router, // es6 写法, 等价于 router: router
render: h => h(App),
}).$mount('#app')
<template>
<div>
<!-- 页面模板中添加 router-view 路由出口 -->
<router-view></router-view>
</div>
</template>
<script>
export default {
}
</script>
<style>
</style>
这样就完成了,我们在浏览器中打开http://localhost:8080/#/home页面就会显示到views/home.vue组件;
打开http://localhost:8080/#/about页面就会显示到views/about.vue组件。
同一页面多个router-view路由出口:
我们也可以同一页面有多个router-view,需要在路由文件要做好相应配置,router-view也要加上name属性;具体操作如下:
let router = new vueRouter({
routes: [
{
path: '/home',
name: 'Home',
components: {
default: Home, // 对应template中没有设置 name 的 router-view
left: Left, // 对应template中 name等于left的 router-view
right: Right // 对应template中 name等于right的 router-view
}
}
]
})
<template>
<div id="app">
<router-link to="/home">Home</router-link>
<!-- 页面模板中添加 router-view 路由出口 -->
<router-view></router-view>
<router-view name="left"></router-view>
<router-view name="right"></router-view>
</div>
</template>
router-link使用:
在template中使用router-link标签用于路由跳转
<template>
<div>
<router-link to="Home">Home</router-link>
<router-link to="About">About</router-link>
<!-- 页面模板中添加 router-view 路由出口 -->
<router-view></router-view>
</div>
</template>
router-link可以设置以下属性
- to:用于指定跳转的路径 (to里的值可以是一个字符串路径,或者一个描述地址的对象);具体如下:
1)字符串
<router-link to="/home"> to home</router-link>
2)对象
<router-link :to="{path:'/home'}"> to home</router-link>
3)命名路由
<router-link :to="{name: 'Home'}"> to home</router-link>
4)直接路由带查询参数query,地址栏变成 /home?color=red
<router-link :to="{path: '/home', query: {color: 'red' }}"> to home</router-link>
5) 命名路由带查询参数query,地址栏变成/home?color=red
<router-link :to="{name: 'home', query: {color: 'red' }}"> to home</router-link>
6)直接路由带路由参数params,params 不生效,如果提供了 path,params 会被忽略
<router-link :to="{path: '/home', params: { color: 'red' }}"> to home</router-link>
7)命名路由带路由参数params,地址栏是/home/red
<router-link :to="{name: 'home', params: { color: 'red' }}"> to home</router-link>
- tag:tag可以指定之后渲染成什么组件,比如我们下面的代码会被渲染成一个
<li>
元素,而不是<a>
如:<router-link to='/home' tag='li'>
; - replace:replace不会留下history记录,所以指定replace的情况下,后退键返回不能返回到上一个页面中;
- active-class:当对应的路由匹配成功时,会自动给当前元素设置一个router-link-active的class,设置active-class可以修改默认的名称。
三、路由嵌套 children
我们也可以嵌套多层路由,具体操作如下:
js里面:在配置路由规则时加上children字段:
//创建路由对象,配置路由规则
let router = new vueRouter({
routes: [
{
path: '/home',
name: 'Home',
component: Home,
children: [ // 添加children字段配资子路由
{
path: "left",
component: Left
},
{
path: "right",
component: Right
}
]
}
]
})
在home.vue页面中添加<router-view></router-view>
标签,作为子路由的出口
<template>
<div>
<div>home page</div>
<router-view></router-view>
</div>
</template>
在浏览器中打开http://localhost:8080/#/home/left 显示出home页面,并且在home页面的<router-view></router-view>
标签的位置嵌入left页面的内容。
四、动态路由
在开发实践中我们可能会遇到用户登录,根据不同用户权限可以访问不同页面的情况;这就是前端鉴权。具体实现是:
- 用户登录返回token
- 携带token请求用户权限列表
- 根据返回的用户权限列表去过滤出当前用户可访问的路由列表
- 使用addRoutes方法将该列表添加到路由中
addRoutes具体用法如下:
this.$router.addRoutes([
{
path: "/user",
name: "user",
component: () => import("@/views/user")
},
...
]);
五、路由跳转方式及传参方式
一、跳转方式
- router-link
- this.$router.push()
- this.$router.replace()
- this.$router.go(n)
二、传参方式
1. query传参
this.$router.push({name:'home',query: {id:'1'}})
this.$router.push({path:'/home',query: {id:'1'}})
// html 取参 $route.query.id
// script 取参 this.$route.query.id
2. params传参
this.$router.push({name:'home',params: {id:'1'}}) // 只能用 name
// 路由配置 path: "/home/:id" 或者 path: "/home:id" ,
// 不配置path ,第一次可请求,刷新页面id会消失
// 配置path,刷新页面id会保留
// html 取参 $route.params.id
// script 取参 this.$route.params
3. query和params区别
query类似 get, 跳转之后页面 url后面会拼接参数,类似?id=1, 非重要性的可以这样传, 密码之类还是用params刷新页面id还在
params类似 post, 跳转之后页面 url后面不会拼接参数 , 但是刷新页面id 会消失(如果路由中配置的话刷新不会消失)
六、路由守卫
路由守卫分为三种:
1.路由独享守卫
2.全局路由守卫
3.组件内守卫 3个
1.路由独享守卫 1个
beforeEnter
2.全局路由守卫
beforeEach
afterEach
beforeResolve(2.5+)
3.组件内守卫 3个
beforeRouteEnter (to, from, next) {
// 在渲染该组件的对应路由被 confirm 前调用
// 不!能!获取组件实例 `this`
// 因为当守卫执行前,组件实例还没被创建
},
beforeRouteUpdate (to, from, next) {
// 在当前路由改变,但是该组件被复用时调用
// 举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候,
// 由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。
// 可以访问组件实例 `this`
},
beforeRouteLeave (to, from, next) {
// 导航离开该组件的对应路由时调用
// 可以访问组件实例 `this`
}
执行顺序
一、打开页面的任意一个页面,没有发生导航切换。
- 全局前置守卫beforeEach (路由器实例内的前置守卫)
- 路由独享守卫beforeEnter(激活的路由)
- 组件内守卫beforeRouteEnter(渲染的组件)
- 全局解析守卫beforeResolve(路由器实例内的解析守卫)
- 全局后置钩子afterEach(路由器实例内的后置钩子)
二、如果是有导航切换的(从一个组件切换到另外一个组件)
- 组件内守卫beforeRouteLeave(即将离开的组件)
- 全局前置守卫beforeEach (路由器实例内的前置守卫)
- 组件内守卫beforeRouteEnter(渲染的组件)
- 全局解析守卫beforeResolve(路由器实例内的解析守卫)
- 全局后置钩子afterEach(路由器实例内的后置钩子)
完整的导航解析流程
- 导航被触发。
- 在失活的组件里调用 beforeRouteLeave 守卫。
- 调用全局的 beforeEach 守卫。
- 在重用的组件里调用 beforeRouteUpdate 守卫 (2.2+)。
- 在路由配置里调用 beforeEnter。
- 解析异步路由组件。
- 在被激活的组件里调用 beforeRouteEnter。
- 调用全局的 beforeResolve 守卫 (2.5+)。
- 导航被确认。
- 调用全局的 afterEach 钩子。
- 触发 DOM 更新。
- 调用 beforeRouteEnter 守卫中传给 next的回调函数,创建好的组件实例会作为回调函数的参数传入。