前言
本文整理了VueRouter的基本使用以及底层原理理解相关知识总结,如果对答案有不一样见解的同学欢迎评论区补充讨论,当然有问题,也欢迎在评论区指出。
一、vueRouter基本使用
从上到下匹配路由,匹配不到路由就会报错,所以一般会在最后一个路由设置为通配符路由。
1、路由懒加载( 动态加载路由 )
(一)未使用懒加载
import Vue from 'vue';
import Router from 'vue-router';
import HelloWorld from '@components/HelloWorld';
Vue.use(Router);
export default new Router({
routes:[
{
path:'./',
name:'HelloWorld',
component:HelloWorld,
//路由的元信息
meta:{keepAlive:true}
}
]
})
(二)使用import异步引入组件
有时候我们想把某个路由下的所有组件都打包在同个异步块 (chunk) 中。只需要使用 命名 chunk,一个特殊的注释语法来提供 chunk name (需要 Webpack > 2.4)。
// 下面2行代码,没有指定webpackChunkName,每个组件打包成一个js文件。
/* const Home = () => import('@/components/home')
const Index = () => import('@/components/index')
const About = () => import('@/components/about') */
// 下面2行代码,指定了相同的webpackChunkName,会合并打包成一个js文件。 把组件按组分块
const Home = () => import(/* webpackChunkName: 'ImportFuncDemo' */ '@/components/home')
const Index = () => import(/* webpackChunkName: 'ImportFuncDemo' */ '@/components/index')
const About = () => import(/* webpackChunkName: 'ImportFuncDemo' */ '@/components/about')
// 打包的webpackChunkName的js文件
{
path: '/about',
component: About
}, {
path: '/index',
component: Index
}, {
path: '/home',
component: Home
}
(三)使用require异步引入组件
{
path: '/home',
name: 'home',
component: resolve => require(['@/components/home'],resolve)
},{
path: '/index',
name: 'Index',
component: resolve => require(['@/components/index'],resolve)
},{
path: '/about',
name: 'about',
component: resolve => require(['@/components/about'],resolve)
}
(四)使用webpack提供的require.ensure()异步引入组件
//语法:require.ensure(dependencies: String[], callback: function(require), chunkName: String)
{
path: '/home',
name: 'home',
component: r => require.ensure([], () => r(require('@/components/home')), 'demo')
}, {
path: '/index',
name: 'Index',
component: r => require.ensure([], () => r(require('@/components/index')), 'demo')
}, {
path: '/about',
name: 'about',
component: r => require.ensure([], () => r(require('@/components/about')), 'demo-01')
}
2、router-link和router-view组件使用
//App.vue
<template>
<div id="app">
<div id="nav">
<!-- 使用 router-link 组件来导航. -->
<!-- 通过传入 `to` 属性指定链接. -->
<!-- <router-link> 默认会被渲染成一个 `<a>` 标签 -->
<router-link to="/home">Home</router-link> |
<router-link to="/about">About</router-link> |
<router-link :to="{ name: 'user', params: { userId: 123 }}">User</router-link>
</div>
<!-- 路由出口 -->
<!-- 路由匹配到的组件将渲染在这里 -->
<router-view/>
</div>
</template>
3、this.$router和this.$route使用
在任何组件内可以通过
this.$router访问路由器,也可以通过this.$route访问当前路由
$router是VueRouter的实例,在script标签中想要导航到不同的URL
- vue组件内(el-menu)切换路由
//导航栏跳转
<el-menu
:default-active="this.$route.path"
router mode="horizontal"
</menu>
- this.$router.push()切换路由的两种方式
this.$router.push({
path:'/fillinformation',
query: {
applicationNo: this.applicationNo,
contractNo:this.contractNo
}
})
this.$route.query.applicationNo//页面跳转后获取携带参数applicationNo参数
//此用法参数会展示在跳转地址上
this.$router.push({
name: 'clientdetail',
params: {
clientCode: clientCode,
clientType: clientType
}
})
this.$route.params.clientCode//页面跳转后获取携带参数clientCode
//此用法参数不会展示在跳转地址
- this.$router.replace({path:'home'});//替换路由,没有历史记录
- this.$router.go(-1),在 history 记录中向前或者后退多少步,类似
window.history.go(n)
$route为当前router跳转对象。可以从中获取当前路由的name,path,query,parmas等
- $route.path 字符串,等于当前路由对象的路径,会被解析为绝对路径,如
"/home/news"。 - $route.params 对象,包含路由中的动态片段和全匹配片段的键值对
$route.query对象,包含路由中查询参数的键值对。例如,对于/home/news/detail/01?favorite=yes,会得到$route.query.favorite == 'yes'。- $route.router 路由规则所属的路由器(以及其所属的组件)。
- $route.matched 数组,包含当前匹配的路径中所包含的所有片段所对应的配置参数对象。
- $route.name 当前路径的名字,如果没有使用具名路径,则名字为空。
4、捕获所有路由或 404 Not found 路由(处理页面)
常规参数只会匹配被 / 分隔的 URL 片段中的字符。如果想匹配任意路径,我们可以使用通配符 (*),匹配所有路径:
{
// 会匹配以 `/user-` 开头的任意路径
path: '/user-*'
}
{
// 会匹配所有路径,优先级从上到下查找路由,都没有的时候全部指向 404页面
path: '*',
redirect:"/404"
}
以上这种找不到页面,重定向到404页面,有个严重缺陷:
- 缺点:如果项目中添加了判断token失效跳出登录然后记住当前页面,登录时候自动跳转到上次token失效的页面,就会有问题,如果故意输入不存在的路由就会在404,失效退出然后登陆后就会自动跳到这个404页面,那样就尴尬了;如果没有这个功能,用上述方法还是比较好使的
解决方法:
- 在index.js文件中注释刚刚加入的path:* 这些东西
- 在router.beforeEach 里面使用 to.matched 匹配出的路由个数来作为判断条件,匹配不到路由就跳转到404页面
pemmision.js
import router from './router'
import { getCookie } from './utils/auth'
// 通过beforeEach钩子来判断用户是否登陆过 有无token
const whiteList = ['/login'] // 不重定向白名单
// const userInfo = getUserInfo()
router.beforeEach((to, from, next) => {
console.log(to.matched)
// 判断是否有登录过
if (getCookie('userId_dev')) {
// 如果包含userId_dev 从登录页面跳转 直接跳转到首页 /
if (to.path === '/login') {
next()
} else {
if (to.matched.length === 0) {
next('/404') // 判断此跳转路由的来源路由是否存在,存在的情况跳转到来源路由,否则跳转到404页面
}
next() // 如果匹配到正确跳转
}
// 没有登录
} else {
if (whiteList.indexOf(to.path) !== -1) {
next()
} else {
// 还没有登录过 则跳转到登录界面
// next('/login')
if (to.path.slice(1) !== '') {
if (to.matched.length === 0) {
router.push({
path: '/login'
})
} else {
router.push({
path: '/login',
query: {
redirect: to.path.slice(1)
}
})
}
} else {
router.push({
path: '/login'
})
}
}
}
})
5、重定向
重定向也是通过 routes 配置来完成,下面例子是从 /a 重定向到 /b:
const router = new VueRouter({
routes: [
{ path: '/a', redirect: '/b' }
]
})
重定向的目标也可以是一个命名的路由:
const router = new VueRouter({
routes: [
{ path: '/a', redirect: { name: 'foo' }}
]
})
甚至是一个方法,动态返回重定向目标:
const router = new VueRouter({
routes: [
{ path: '/a', redirect: to => {
// 方法接收 目标路由 作为参数
// return 重定向的 字符串路径/路径对象
}}
]
})
6、导航守卫
完整的导航解析流程
- 导航被触发。
- 在失活的组件里调用
beforeRouteLeave守卫。 - 调用全局的
beforeEach守卫。 - 在重用的组件里调用
beforeRouteUpdate守卫 (2.2+)。 - 在路由配置里调用
beforeEnter。 - 解析异步路由组件。
- 在被激活的组件里调用
beforeRouteEnter。 - 调用全局的
beforeResolve守卫 (2.5+)。 - 导航被确认。
- 调用全局的
afterEach钩子。 - 触发 DOM 更新。
- 调用
beforeRouteEnter守卫中传给next的回调函数,创建好的组件实例会作为回调函数的参数传入。
7、路由过渡动效
看官方router.vuejs.org/zh/guide/ad…
二、vueRouter底层原理
在使用 Vue 等前端渲染时,通常会有 hash 路由和 history 路由两种路由方式。其实现方式也有所不同
- hash 路由:监听 url 中 hash 的变化,然后渲染不同的内容,这种路由不向服务器发送请求,不需要服务端的支持;
- history 路由:监听 url 中的路径变化,需要客户端和服务端共同的支持;
1、hash 路由
当页面中的 hash 发生变化时,会触发 hashchange 事件,因此我们可以监听这个事件,来判断路由是否发生了变化,如果变化了,调用onHashChange函数,实现页面的切换
window.addEventListener('hashchange', () => {
history.onHashChange()
})
针对于 HTML5History 和 HashHistory 特殊处理,因为在这两种模式下有可能存在进入时候的不是默认页,需要根据当前浏览器地址栏里的 path 或者 hash 来激活对应的路由,此时就是通过调用 transitionTo 来达到目的
history.transitionTo(getHash(), () => {
window.addEventListener('hashchange', () => {
history.onHashChange()
})
})
2、history 路由
在 history 路由中,我们一定会使用 window.history 中的方法,常见的操作有:
- back():后退到上一个路由
- forward():前进到下一个路由,如果有的话
- go(number):进入到任意一个路由,正数为前进,负数为后退
- pushState(obj, title, url):前进到指定的 URL,不刷新页面
- replaceState(obj, title, url):用 url 替换当前的路由,不刷新页面
popstate可监听路由变化
- pushState 和 replaceState 被调用时,是不会触发触发popstate 事件
- 前三个方法会触发popstate事件,实现页面的切换
调用以上几种方式时,仅修改页面的 URL,而不发送请求
location.href 和 location.replace 切换时要向服务器发送请求
总结
觉得写得好的,对你有帮助的,可以分享给身边人,知识越分享越多,千万不要吝啬呀
后续更新vue底层相关原理讲解,请关注我,整理好,分享给你们,我们一起学前端