共计 8341 个字符,预计需要花费 21 分钟才能阅读完成。
Vue-Router 路由治理
- 根底应用
- 进阶
1 根底
- 装置与根本应用
- 动静路由
- 嵌套路由
- 编程式导航
- 命名路由
- 命名视图
- 重定向和别名
- 路由组件传参
- History 模式
- Modules
1.1 装置与根本应用
// 装置
npm install vue-router --save
//main.js 内引入
import VueRouter from 'vue-router'
Vue.use(VueRouter)
// 此时在 vue 实例上会多出 `$route` 和 `$router` 两个属性
创立两个页面
//About.vue
<template>
<div> 对于页面 </div>
</template>
//Detail.vue
<template>
<div> 对于页面 </div>
</template>
配置路由
//router.js 文件
import VueRouter from "vue-router";
import About from './pages/About'
import Detail from './pages/Detail'
export const router = new VueRouter({
routes: [
{
path: '/about',
component: About,
},
{
path: '/detail',
component: Detail
}
]
})
- 引入 VueRouter 并实例化,引入组件
- 配置对象的
routes
选项,以数组 - 对象
模式 注册路由,包含门路与组件
在 mian.js 中引入 router 实例并注册
//mian.js
import {router} from './router'
new Vue({
router,
render: h => h(App),
}).$mount('#app')
// 此时能够察看到 $router 与 $route 的相干配置
在 App.vue 中应用路由
<template>
<div id="app">
<router-link to="/about"> 跳转 about</router-link><br />
<router-link to="/detail"> 跳转 detail</router-link>
<router-view></router-view>
</div>
</template>
<script>
export default {name: "App",};
</script>
router-link
为路由入口
,在 to 中配置门路router-view
为路由进口
,跳转的页面在此处显示
相似于动静组件
,实现了根本的跳转性能,路由的性能更加弱小
$router 相似于 $store,在根实例注册后, 子组件 都能够拜访到原 路由实例,不须要频繁的在子组件中引入。$route 是以后路由
1.2 动静路由
依据不同的门路参数跳转至同一组件,显示不同的数据
//router.js
{
path: '/about:id',
component: About,
},
//App.vue
<template>
<div id="app">
<router-link to="/about/:'1'"> 用户 1 </router-link><br />
<button @click="to"> 用户 2 </button>
<router-view></router-view>
</div>
</template>
<script>
export default {
name: "App",
methods: {to() {this.$router.push('/about/:"2"');
},
},
};
</script>
//About.vue
<template>
<div> 对于页面{{userId}}</div>
</template>
<script>
export default {
computed: {userId() {return this.$route.params.id;},
},
};
</script>
- 在 router 中注册的门路增加
:param
- 跳转时能够应用 router-link 或者应用 $router.push,门路中携带参数
-
在跳转至的路由能够通过 $route.params 拜访动静门路的参数
能够依据参数去申请数据再渲染页面
:
,对应定义的是 params 参数-
? = &
,能够定义 query 参数,通过 $route.query 拜访<router-link to="/about/?id=1"> 用户 1 </router-link><br />
通配符
捕捉所有路由或 404 Not found 路由
{ // 匹配所有门路
path:'*'
}
{ // 匹配以 '/user' 结尾的任意门路
path:'/user-*'
}
应用通配符路由时,$route.params 会增加一个名为 pathMatch 参数。蕴含 URL 通配符匹配的局部
//router.js
{
path: '*',
component: () => import('./pages/Notfound')
}
当跳转的门路匹配失败时,能够匹配通配符门路,并通过
pathMatch
参数提醒谬误的门路
应用 ’/user-*’,能够设置特定门路下某种页面未找到的提示信息
1.3 嵌套路由
有时在路由跳转后可能还须要路由跳转,这时就须要嵌套多级路由
在路由注册时增加 children
属性
//router.js
{
path: '/about',
component: About,
children: [
{
path: 'child',
component: () => import('./pages/Child')
}
]
},
// 跳转
<router-link to="/about/child"> 二级跳转 </router-link>
子路由的门路前不须要
/
,不然会认为从跟门路开始
1.4 编程式导航
除了应用 router-link申明式
创立 a 标签的形式进行跳转,也能够是借助 router 的实例办法 编程式
实现跳转
push:向 history 栈 增加
一个新的记录,能够点击浏览器的后退至之前的 URL
replace:替换
以后的 history 栈顶记录
go(n):后退或后退 |n| 步,正数为后退,负数为后退,记录不够用则失败
this.$router.push({
path: "/detail",
// params: {userId: 123},
query: {user: "张三"},
});
push 中的数据能够应用 对象模式 ,params 参数 不能 与 path同时应用 ,router-link 中的
to
也反对对象模式的写法
能够应用name
属性传递 params 参数
params
参数:必须 在门路 上增加参数名,并且跳转时应用 name 属性-
query
参数:不用在注册时在 门路 上增加信息,跳转时应用 path 或 name 都可当在门路中增加了参数,然而跳转时没有传递 params 参数,也会跳转失败
应用 name 属性时,反对同时传递 params 与 query 参数
1.5 命名路由
上述曾经对 name 进行了一些介绍,是对路由的命名
能够简化门路过长的问题,同时防止 params 参数的问题
routes: [
{
path: '/user/:userId',
name: 'user',
component: User
}
]
1.6 命名视图
router-view 中能够增加 name
属性,对应路由中的组件
注册路由时的 components 能够是对象模式,蕴含多个组件,key 提供给 name 抉择
//router.js
{
name: 'detail',
path: '/detail/:userId',
components: {
default: Detail,
a: () => import('./pages/Ads')
}
},
// 视图
<router-view></router-view>
<router-view name="a"></router-view>
没有 name 属性的视图,应用
default
的组件
1.7 重定向和别名
重定向
拜访 ’/a’ 重定向 ’/b’,URL 与匹配的路由都换成 ’/b’
// 门路
routes: [{ path: '/a', redirect: '/b'}
]
// 命名
routes: [{ path: '/a', redirect: { name: 'foo'}}
]
// 动静办法
routes: [
{ path: '/a', redirect: to => {
// 办法接管 指标路由 作为参数
// return 重定向的 字符串门路 / 门路对象
}}
]
能够在返回主页时将根门路重定向为子路由门路,保障页面的填充
别名
‘/a’ 的别名 ’b’,当拜访 ’/b’ 时,URL 依然是 ’/b’,然而路由匹配为 ’/a’,相当于拜访 ’/a’,只是名字不同
routes: [{ path: '/a', component: A, alias: '/b'}
]
能够自在地将 UI 构造映射到任意的 URL,不受限与配置的嵌套的路由构造
1.8 路由组件传参
props
属性:boolean|Object|Function
$route 会使组件与对应路由高耦合,导致组件只能在特定的 URL 上应用,限度灵活性。
应用 props 属性能够将组件和路由 解耦
// 对象模式
{
name:'detail',
path:'/detail',
component:Detail,
props:{foo:'a',bar:'b'}
}
在 Detail组件中 ,能够间接在props 中申明 后应用
对象模式传递的是静态数据,在配置的时候就写好的,应用场景较少
// 布尔模式
{
...
props:true,
}
// 多组件
{
...
components:{Detial,Ads},
props:{Detail:true,Ads:false}
}
将路由跳转时的
params
参数传入组件中,在组件的 props 中申明后应用
// 函数模式
{
...
props($route){
return {
id:$route.params.userId,
name:$route.query.user
}
}
}
// 解构赋值简写 - 相似于 vuex 的 action 中的 context 对象
{
...
props({params,query}){
return {
id:params.userId,
name:query.user
}
}
}
在不应用 props 的状况下,传递的参数全副都在 URL 上,须要应用计算属性一一获取
应用 props 的函数模式,能够将 params 和 query 参数以及静态数据在组件中的 props 中申明
这样简化了取值的操作,解耦合
1.9 History 模式
router 中的配置除了 routes
选项外,还要其余选项,例如 mode
mode 默认为 hash,地址栏会有一个#
号,URL 扭转时,页面不会从新加载
更改为失常的网址模式,应用 mode:'history'
history 模式须要肯定的 后盾反对
,不然会呈现 404
这是因为 hash 模式下 #后的地址作为路由跳转,不会发动 http 申请,然而在 history 模式下,刷新页面时,会发动 http 申请,因为没有# 的分隔会将整个地址都作为申请地址
nginx
location / {try_files $uri $uri/ /index.html;}
Node.js
const http = require('http')
const fs = require('fs')
cosnt httpPort = 80
http.createServer((req,res)=>{fs.readFile('index.html','utf-8',(err,content)=>{if(err){...}
res.writeHead(200,{'Content-Type':'text/html;charset=utf-8'})
res.end(content)
})
}).listen(httpPort,()=>{console.log('Server listening on:http://loaclhost:%s',httpPort)
})
能够在 Node.js 中应用
connect-history-api-fallback
插件,疾速解决 history 模式后端地址和前端路由地址的抵触,造成申请失败
2.10 Modules
当嵌套路由的层级过多时,能够将其宰割成多个模块
与 vuex 拆分的形式相似,不必创立 module 数组,引入后间接在 routes 数组中注册即可
//routers 文件夹中的 index.js 入口文件
import VueRouter from 'vue-router'
import {about} from './modules/about'
import {detail} from './modules/detail'
import {Notfound} from './Notfound'
export const router = new VueRouter({
routes: [{ path: '/'},
about,
detail,
Notfound
]
})
批改为模块化后须要从新在 main.js 中引入并注册
2 进阶
- 路由守卫
- 路由元信息
- 过渡动效
- 数据获取
- 滚动行为
- 路由懒加载
- 导航故障
2.1 路由守卫
- 全局前置守卫
- 全局解析守卫
- 全局后置钩子
- 路由独享守卫
- 组件内的守卫
- 整体流程
2.1.1 全局前置守卫
beforeEach
const router = new VueRouter({})
router.beforeEach((to,from,next)=>{})
- to : 指标路由
- from : 来到的路由
-
next : 放行函数,
无参数
间接跳转至指标路由- next(false) 中断以后导航
- next(‘/’)或 next({path:’/’}) 指定路由跳转,能够应用
name
以及其余选项 - next(error) 中断以后导航,并将 Error 实例传入 router.onError()执行回调
- next 函数仅能被调用一次
//index.js - 模仿未登录用户拜访页面,重定向至登录页面
router.beforeEach((to, from, next) => {if (to.name !== 'login' && to.name !== 'register' && !isAuthenticated) {next({ name: 'login'})
} else {next()
}
})
如果跳转应用的 push 的形式,被守卫拦挡重定向后会报错,但不影响应用
能够在 push 后应用 catch 捕捉谬误
2.1.2 全局解析守卫
beforeResolve
相似于 beforeEach
区别:在导航被确认之前,同时在所有 组件内守卫 和异步路由组件 被解析之后,解析守卫被调用
2.1.3 全局后置钩子
afterEach
与守卫不同的是没有 next 放行函数
router.afterEach((to, from) => {// ...})
2.1.4 路由独享守卫
beforeEnter
与全局不同的在于它作为一个路由的配置项,独自管制一个路由
routes: [
{
path: '/foo',
component: Foo,
beforeEnter: (to, from, next) => {// ...}
}
]
to : 跳转至以后路由
from : 由某路由跳转来
能够限度 from 能够从何处跳转至该路由
2.1.5 组件内的守卫
在组件中作为配置 选项
beforeRouteEnter:相似于独享守卫,在组件实例创立前调用,故不能获取 vm 实例
能够在 next 中增加回调函数拜访组件实例
beforeRouteEnter (to, from, next) {
next(vm => {// 通过 `vm` 拜访组件实例})
}
beforeRouteUpdate:门路扭转,组件被复用时调用,能够拜访 vm 实例
此时的 this 代表的时 from 的路由组件实例
beforeRouteLeave:来到该组件的对应路由时调用,能够拜访该组件 vm 实例
能够在来到前对组件中的内容进行判断,确认是否来到
2.1.6 整体流程
2.2 路由元信息
meta 配置项,存储路由元信息
在间断的路由嵌套中,每一层的路由信息都会被收集到 $route.matched数组
中
能够应用数组的遍历办法遍历 matched 数组对 meta 字段进行查看
router.beforeEach((to, from, next) => {if (to.matched.some(record => record.meta.requiresAuth)) {
// this route requires auth, check if logged in
// if not, redirect to login page.
if (!auth.loggedIn()) {
next({
path: '/login',
query: {redirect: to.fullPath}
})
} else {next()
}
} else {next() // 确保肯定要调用 next()}
})
2.3 过渡动效
router-view 是根本的动静组件,相当于 component 标签
所以能够应用 transition 标签对其进行包裹实现 过渡
成果
同样的应用 keep-alive 实现组件 缓存
transition 与 keep-alive
2.4 数据获取
在路由跳转时常常会随同着从服务器获取数据
导航实现后申请:实现导航后,在组件的申明周期钩子中申请数据。申请实现期间显示 ” 加载 ” 提醒。
应用 v -if 条件渲染加载页面、谬误页面以及申请胜利页面
在 created 钩子中申请数据
导航实现前申请:在路由守卫中获取数据,获取胜利后执行导航
beforeRouteEnter 中申请数据,在 next()
回调
中配置申请取得的数据
2.5 滚动行为
scrollBehavior 配置选项
切换至新路由时,页面滚动到顶部或者放弃原先的滚动地位
const router = new VueRouter({routes: [...],
scrollBehavior (to, from, savedPosition) {// return 冀望滚动到哪个的地位}
})
默认状况下不产生滚动,返回 svaedPosition 时后退 / 后退与浏览器原生操作统一
return {x:0,y:0}
依据坐标间接滚动
meta:{x:0,y:0}
return {
selector:to.meta,
behavior:'smooth'
}
依据元信息进行
平滑滚动
return new Promise((resolve, reject) => {setTimeout(() => {resolve({ x: 0, y: 0})
}, 500)
})
能够返回一个 Promise,resolve 中传入滚动信息,实现
异步滚动
2.6 路由懒加载
异步组件
// 异步组件工厂函数
const AsyncComponent = (url) => ({// 须要加载的组件 (应该是一个 `Promise` 对象)
component: import(url),
// 异步组件加载时应用的组件
loading: LoadingComponent,
// 加载失败时应用的组件
error: ErrorComponent,
// 展现加载时组件的延时工夫。默认值是 200 (毫秒)
delay: 200,
// 如果提供了超时工夫且组件加载也超时了,// 则应用加载失败时应用的组件。默认值是:`Infinity`
timeout: 3000
})
应用 import()函数异步引入组件,能够在首次渲染时先不下载局部组件
在拜访异步组件时再进行下载
2.7 导航故障
在路由导航失败时能够在 push 后链式处理错误信息
- isNavigationFailure(failure,NavigationFailureType)
-
NavigationFailureType
- redirected: 调用了 next(newLocation) 重定向到了其余中央
- aborted: 调用了 next(false) 中断了本次导航
- cancelled: 以后导航还没有实现之前又有了一个新的导航
- duplicated: 导航被阻止,因为咱们曾经在指标地位了
import VueRouter from 'vue-router'
const {isNavigationFailure, NavigationFailureType} = VueRouter
// 正在尝试拜访 admin 页面
router.push('/admin').catch(failure => {if (isNavigationFailure(failure, NavigationFailureType.redirected)) {
// 向用户显示一个小告诉
showToast('Login in order to access the admin panel')
}
})
// 正在尝试拜访 admin 页面
router.push('/admin').catch(failure => {if (isNavigationFailure(failure, NavigationFailureType.redirected)) {
failure.to.path // '/admin'
failure.from.path // '/'
}
})