1.什么是vue-router
vue-router是vue.js官方给出的路由解决方案,只能结合vue项目进行使用,能够轻松的管理SPA项目中组件的切换
2.vue-router的用法
先安装vue-router (npm i vue-router)
在新建router/index.js 文件,在文件内导入Vue和vue-router(新建的路径由自己决定)
// 导入Vue和VueRouter的包
// router/index.js文件
import Vue from 'vue'
import VueRouter from 'vue-router'
// 调用Vue.use()函数,把VueRouter安装为Vue的插件
Vue.use(VueRouter)
const Home = () => import("../home.vue");
// 创建路由的实例对象
const router = new VueRouter({
// routes是一个数组,定义"hash地址"与"组件"之间的关系
routes:[
// 重定向属性,当刚打开页面,并没有点击跳转时,则设置首页面渲染
{path: '/',redirect: '/home'},
{path: '/home',component: Home}
]
})
// 导出的目的是为了在main.js进行导入, 将路由实例对象挂载在 new Vue()里面
export default router
在组件中vue-router的用法
// app.vue组件
<template>
<div>
// router-link来替代普通的a连接 to为组件路径
<router-link to='/home'></router-link>
// 只要在项目中安装和配置了vue-router,就可以使用router-view这个组件
// 作用 : 占位符,表示渲染的内容的位置
<router-view></router-view>
</div>
</template>
嵌套路由的使用
import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter)
//懒加载,打包的时候会分离,使用的时候才会加载 可减小js体积
const Home = () => import('Home.vue')
const tab = () => import('Tab.vue')
const router = new VueRouter({
routes: [
{
path: '/home',
component: Home,
// 子路由的重定向
redirec: '/home/tab',
// 子路由
children: [
// 默认子路由 如果children中的path为空,则这条路由规则,就叫做默认子路由
{
path: 'tab', // 子路由路径不用加/
component: Tab
}
]
}
]
})
export default router
// app.vue组件
<template>
<div>
// 路径为子路径,点击后跳转到子路径
<router-link to='/home/tab'></router-link>
// 若使用的是默认子路由,则to后面 /tab可以省略
<router-link to='/home'></router-link>
<router-view></router-view>
</div>
</template>
3.动态路由的使用
// 需求: 在Movie组件中,希望根据id的值,展示对应电影的详情信息
// 这里path路径中有参数,可以开启props传参,是为了方便Movie组件拿到参数值
// 在对象中加入props:true
// 如果路径中没有参数,则开启props传参也没有意义
{path: '/movie/:id',component: Movie,props: true}
// id的值会存在放Vue实例中的 $route.params.id中
// Movie.vue
//则这里就可以直接拿到id的值
props: ['id']
命名路由
import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter)
const Home = { template: '<div>This is Home</div>' }
const Foo = { template: '<div>This is Foo</div>' }
const Bar = { template: '<div>This is Bar {{ $route.params.id }}</div>' }
const router = new VueRouter({
mode: 'history',
base: __dirname,
routes: [
{ path: '/', name: 'home', component: Home },
{ path: '/foo', name: 'foo', component: Foo },
{ path: '/bar/:id', name: 'bar', component: Bar }
]
})
new Vue({
router,
template: `
<div id="app">
<h1>Named Routes</h1>
<p>Current route name: {{ $route.name }}</p>
<ul>
<li><router-link :to="{ name: 'home' }">home</router-link></li>
<li><router-link :to="{ name: 'foo' }">foo</router-link></li>
// 若这里是path,则不可以写params,写了不会生效
<li><router-link :to="{ name: 'bar', params: { id: 123 }}">bar</router-link></li>
</ul>
<router-view class="view"></router-view>
</div>
`
}).$mount('#app')
多个路由指向同一个组件时,组件内的生命周期钩子不会被调用了,这是因为组件被复用了,如以下代码都是指向Home组件
const routes = [
{
path: '/home',
component: Home
},
{
path: '/about',
component: Home
}
]
// 使用watch则可以进行监听,对路由参数做出响应
watch: {
'$route'(to,from){
console.log(from)
}
}
// 也可以在组件内使用如下
beforeRouteUpdate(to, from, next) {
// react to route changes...
// don't forget to call next()
}
扩展:
a.在hash地址中,/后面的参数项,叫做’路径参数’,路由中路径参数放在params中
b.在hash地址中,?后面的参数项,叫做”查询参数”,路由中查询参数放在query中
c.在this.$route中,path只是路径部分,不包含查询参数,而fullPath则是完整路径
4.路由守卫
记住参数或查询的改变并不会触发进入/离开的导航守卫(这个是指组件内的beforeRouteEnter)。你可以通过观察 $route 对象(watch)来应对这些变化,或使用 beforeRouteUpdate 的组件内守卫。
注意: 如果是全局守卫和组件内的beforeRouteUpdate和beforeRouteLeave在动态路由跳转时也会调用触发守卫
全局前置路由守卫
// router/index.js
// to是将要访问的路由的对象
// from 是将要离开的路由的对象
// next是一个函数,调用next() 表示放行,允许这次路由导航
router.beforeEach((to,from,next) => {
next();
})
// next函数的3中调用方式
// 当前用户拥有后台主页的访问权限,直接放行 next();
// 当前用户没有后台主页的访问权限,强制跳转登录页面 next('/login')
// 当前用户没有后台主页的访问权限,不允许跳转到后台主页 next(false);
使用场景:使用前置路由守卫模拟登录(代码展示)
router.beforeEach((to, from, next) => {
// 判断要跳转的页面是不是登录页,如果是的话,就直接同意跳转
if (to.path === '/login') {
return next();
}
// 如果不是,则判断浏览器里是否存储了token值,判断登录是否过期,如果不存在token或者过期
//则强制跳转到登录页重新进行登录
else if (!localStorage.getItem('token')) {
return next('/login');
}
// 最后则是有token值,则让其正常跳转
next();
})
以上则是一个模拟登录功能的简单实现,但以上功能还没有完善,只是大概结合全局前置路由守卫进行实现
全局后置钩子
// 不会接受 next 函数也不会改变导航本身:
router.afterEach((to, from) => {
// ...
})