VueRouter
vue-router用法大全
使用了一段时间 Vue2 + Vuex + VueRouter + Element UI 开发之后
发现仅仅只用到了VueRouter的少数浅层功能 大部分高级功能都没有用到 决定看官方文档学习一下
官方文档是最好的学习笔记(●’◡’●)
API 参考 | Vue Router (vuejs.org)
VueRouter参数配置大全
参数 | 类型 | 默认值 | 可选值 | 描述 |
---|---|---|---|---|
routes | Array | 配置路由规则 | ||
mode | string | “hash” (浏览器环境) /“abstract” (Node.js 环境) | “hash”/“history” / “abstract” | 配置路由模式 |
base | string | / | 应用的基路径 | |
linkActiveClass | string | router-link-exact-active | 全局配置 默认的精确激活的 class | |
scrollBehavior | Function | 配置滚动行为 | ||
parseQuery / stringifyQuery | Function | 提供自定义查询字符串的解析/反解析函数 | ||
fallback | boolean | 当浏览器不支持 history.pushState 控制路由是否应该回退到 hash 模式。默认值为 true |
// 引入 vue-router
import VueRouter from "vue-router";
import Vue from 'vue'
Vue.use(VueRouter)
// 创建 一个路由器
const router = new VueRouter({
routes:[],
// 匹配模式设置
mode:"",
base:"",
// 配置路由被激活时使用的 CSS类名称
// 此时使用 .active{color:blue} 等...
linkActiveClass: 'active',
// 这个功能只在支持 history.pushState 的浏览器中可用
scrollBehavior (to, from, savedPosition) {
// return 期望滚动到哪个的位置
}
parseQuery: function(){},
stringifyQuery: function(){},
// 当浏览器不支持 history.pushState 控制路由是否应该回退到 hash 模式。默认值为 true
fallback:true,
})
// 暴露该路由器
export default router
Mode参数详解
//hash: 使用 URL hash 值来作路由。支持所有浏览器,包括不支持 HTML5 History Api 的浏览器。
//history: 依赖 HTML5 History API 和服务器配置。查看 HTML5 History 模式。
//abstract: 支持所有 JavaScript 运行环境,如 Node.js 服务器端。如果发现没有浏览器的 API,路由会自动强制进入这个模式。
scrollBehavior参数详解
使用前端路由,当切换到新路由时,想要页面滚到顶部,或者是保持原先的滚动位置,就像重新加载页面那样。 vue-router 能做到,而且更好,它让你可以自定义路由切换时页面如何滚动。
scrollBehavior
函数接收 to
和 from
路由对象,如 Navigation Guards。第三个参数 savedPosition
,只有当这是一个 popstate
导航时才可用(由浏览器的后退/前进按钮触发)。
// 该函数可以返回一个 ScrollToOptions 位置对象:
scrollBehavior (to, from, savedPosition) {
// return 期望滚动到哪个的位置
// 1.
// 始终滚动到顶部
return { top: 0 }
// 跳转到 x y 的坐标
return {x:0, y:0}
// 2.
// 你也可以通过 el 传递一个 CSS 选择器或一个 DOM 元素。在这种情况下,top 和 left 将被视为该元素的相对偏移量。
// el: document.getElementById('main'),
return {
// 始终在元素 #main 上方滚动 10px
el: '#main',
top: -10,
}
// 3.
// 如果返回一个 falsy 的值,或者是一个空对象,那么不会发生滚动
// falsy js中所有表达式判断为 false 的值
return false
// 4.
// 如果你要模拟 “滚动到锚点” 的行为
if (to.hash) {
return {
el: to.hash,
// 如果你的浏览器支持滚动行为,你可以让它变得更流畅
// 支持 Window.scroll()
behavior: 'smooth',
}
}
// 5.
// 延迟滚动
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve({ left: 0, top: 0 })
}, 500)
})
}
parseQuery stringifyQuery参数详解
-
stringifyQuery: 序列化传入的query参数,方法可以接收一个对象参数
在
new Router
的时候传递这个属性,在序列化query
参数的就执行这个方法,不会执行默认的方法,序列化后在地址栏显示序列化之后的参数 -
parseQuery: 解析地址栏参数,方法接收一个字符串参数
在
new Router
的时候传递这个属性,在解析query
参数的时候,会执行这个方法,不会在执行默认的方法,
这个方法只解析path
中的参数,或者浏览器刷新的时候的地址栏的参数,不会对在query
参数对处理
this.$router.push({
path: "url?name=snowman",
query: {
password: "qwkejqowr"
}
})
// 简单写一下加密
stringifyQuery(obj){
const res = obj ? Object.keys(obj).map(key => {
const val = obj[key]
if (val === undefined) {
return ''
}
if (val === null) {
return encode(key)
}
return encode(key) + '=' + encode(val)
})
return res
}
Routes参数详解
interface RouteConfig = {
path: string,
component?: Component,
name?: string, // 命名路由
components?: { [name: string]: Component }, // 命名视图组件
redirect?: string | Location | Function,
props?: boolean | Object | Function,
alias?: string | Array<string>,
children?: Array<RouteConfig>, // 嵌套路由
beforeEnter?: (to: Route, from: Route, next: Function) => void,
meta?: any,
// 2.6.0+
caseSensitive?: boolean, // 匹配规则是否大小写敏感?(默认值:false)
pathToRegexpOptions?: Object // 编译正则的选项
}
属性 | 详解 |
---|---|
path | 路径 |
name | 命名路由 |
component | 命名视图组件 |
components | 命名视图组件 |
redirect | 重定向路径 |
alias | 别名 |
children | 嵌套路由 |
meta | 路由元信息 使用$route.meta.属性可以获取 |
caseSensitive | 匹配规则是否大小写敏感?(默认值:false) |
pathToRegexpOptions | 编译正则的选项 |
props | 组件路由传参 |
path参数详解
const routes = [
// 1.
// 匹配 /p/books
// 使用 : 开头代表需要传递参数
// this.route.parmas.orderId 获取
{ path: '/p/:productName' },
// * 表示匹配全部路由
{ path:"*", },
// 2.
// 在参数中自定义正则
// 匹配 /o/3549 仅匹配数字
{ path: '/o/:orderId(\\d+)' },
// 3.
// 可重复的参数
// /:chapters -> 匹配 /one, /one/two, /one/two/three, 等
{ path: '/:chapters+' },
// /:chapters -> 匹配 /, /1, /1/2, /1/2/3, 等
{ path: '/:chapters(\\d+)*' },
// 4.
// 将匹配 /users/posva 而非:
// 对 大小写 敏感
// - /Users/posva 当 sensitive: true
{ path: '/users/:id', sensitive: true },
// 对url末尾的 / 敏感
// - /users/posva/ 当 strict: true
// 将匹配 /users, /Users, 以及 /users/42 而非 /users/ 或 /users/42/
{ path: '/users/:id?' },
// 5.
// 可选参数
// 请注意,* 在技术上也标志着一个参数是可选的,但 ? 参数不能重复。
// 匹配 /users 和 /users/posva
{ path: '/users/:userId?' },
// 匹配 /users 和 /users/42
{ path: '/users/:userId(\\d+)?' },
]
// 官方API文档里没有给出这两个参数 有点疑惑
strict: true
sensitive: true
name参数详解
1.渲染组件
{
path:"/",
component:MainPage,
// 定义name
name:"RouteName"
}
<template>
<div id="app">
<router-view></router-view>
<!-- 将渲染MainPage组件 -->
<router-view name="RouteName"></router-view>
</div>
</template>
2.可以用name传参 使用$route.name获取组件name值
this.$route.name
3.router-link 使用pramas传参必须使用name跳转
<router-link :to="{name:'RouteName',params:{name:'Snowman'}}">ToMainPage</router-link>
component参数详解
{
path:"BlogContent",
// 可以使用函数的方式进行懒加载
component: component: () => import('../views/MusicPlay')
// 也可直接 import后 在此处使用
component: ComponentObject
// 在项目开发中应用中不需要一开始就加载的路由组件请使用懒加载
// 路由的懒加载,通过函数的形式,可以让项目中哪些不许一开始就要加载的组件,加载到项目中去
// 只有浏览器跳转到当前路由时,该路由组件才会加载到项目中去
// 这样做的好处是减少不必要的加载降低应用加载速度和运行带宽
},
components参数详解
有时候想同时 (同级) 展示多个视图,而不是嵌套展示,例如创建一个布局,有 sidebar
(侧导航) 和 main
(主内容) 两个视图,这个时候命名视图就派上用场了。你可以在界面中拥有多个单独命名的视图,而不是只有一个单独的出口。如果 router-view
没有设置名字,那么默认为 default
routes = {
path: '/',
components: {
default: Home,
// LeftSidebar: LeftSidebar 的缩写
LeftSidebar,
// 它们与 `<router-view>` 上的 `name` 属性匹配
RightSidebar,
}
<!-- 展示Components中配置的组件 -->
<router-view class="view left-sidebar" name="LeftSidebar"></router-view>
<router-view class="view main-content"></router-view>
<router-view class="view right-sidebar" name="RightSidebar"></router-view>
redirect参数详解
// 可以使用路径重定向
const routes = [{ path: '/home', redirect: '/' }]
// 不带 / 为相对路径的跳转
const routes = [{ path: '/home', redirect: 'next' }]
// 可以使用路由名称重定向
const routes = [{ path: '/home', redirect: { name: 'homepage' } }]
// 可以是一个方法
// 低配版路由守卫
redirect: to => {
// 方法接收目标路由作为参数
// return 重定向的字符串路径/路径对象
return { path: '/search', query: { q: to.params.searchText } }
},
alias参数详解
const routes = [{ path: '/home', redirect: '/' }]
重定向是指当用户访问 /home
时,URL 会被 /
替换,然后匹配成 /
。那么什么是别名呢?
将 /
别名为 /home
,意味着当用户访问 /home
时,URL 仍然是 /home
,但会被匹配为用户正在访问 /
// 与rediect的区别就是 URL 是否变化
// 定位到 /home 时
// 显示为 /home 但是访问的是 /
const routes = [{ path: '/', component: Homepage, alias: '/home' },
// 可以使用数组提供多个别名
// 绝对相对均可
{ path: '', component: UserList, alias: ['/people', 'list', ''] },
// 路由有参数必须使用 绝对URL
{ path: '/', component: Homepage, alias: '/:id' },]
meta参数详解
- meta的定义:简单来说就是路由元信息,也就是每个路由身上携带的信息。
- meta的作用:vue-router路由元信息说白了就是通过meta对象中的一些属性来判断当前路由是否需要进一步处理,如果需要处理,按照自己想要的效果进行处理即可
我们称呼 routes 配置中的每个路由对象为 路由记录。路由记录可以是嵌套的,因此,当一个路由匹配成功后,他可能匹配多个路由记录
let routes = [
{
path: '/foo',
component: Foo,
children: [
{
path: 'bar',
component: Bar,
// 配置 requiresAuth: true
// 只有经过身份验证的用户才能访问该内容
meta: {
requiresAuth: true,
title: "路由标题 在HTML中展示什么"
}
}
]
一个路由匹配到的所有路由记录会暴露为 $route
对象(还有在导航守卫中的路由对象)的$route.matched
数组。我们需要遍历这个数组来检查路由记录中的 meta
字段,但是 Vue Router 还为你提供了一个 $route.meta
方法,它是一个非递归合并所有 meta
字段的(从父字段到子字段)的方法。这意味着你可以简单地写
// $route.matched 数组为子与父路由的全部 meta信息组成的数组
router.beforeEach((to, from) => {
// 而不是去检查每条路由记录
// some方法遍历数组 如果满足 return条件 为ture 则返回 否则为false
// to.matched.some(record => record.meta.requiresAuth)
if (to.meta.requiresAuth && !auth.isLoggedIn()) {
// 此路由需要授权,请检查是否已登录
// 如果没有,则重定向到登录页面
return {
path: '/login',
// 保存我们所在的位置,以便以后再来
query: { redirect: to.fullPath },
}
}
})
caseSensitive参数详解
是否严格匹配大小写
false:严格匹配
ture:大小写均可匹配
props参数详解
简单案例
// router/index.js 简单示例
// 引入 vue-router
import VueRouter from "vue-router";
import Vue from 'vue'
Vue.use(VueRouter)
// 引入组件
import BlogMainPage from "@/components/BlogPage/BlogMainPage";
// 引入加载动画
import NProgress from 'nprogress'
import 'nprogress/nprogress.css'
// 创建 一个路由器
const router = new VueRouter({
routes: [
{
path:"/",
component:MainPage,
},
{
path:"/BlogMainPage",
component:BlogMainPage,
children:
[
{
path:"BlogContent",
component: BlogContent
},
]
},
{
// :id 可进行路由传参 在 this.$route.params.id 获取
path:"/BlogDetail/:id",
component:BlogDetail
},
{
path:"*",
component:PageNotFound,
}
// path 为 * 表示匹配全部 可以匹配全部路径 路径匹配为从上至下
]
})
// 配置加载条 nprogress 以及加载动画
router.beforeEach((to, from, next) => {
NProgress.start()
next()
})
router.afterEach(() => {
NProgress.done()
})
// 暴露该路由器
export default router
路由守卫
官方文档:https://router.vuejs.org/zh/guide/advanced/navigation-guards.html
正如其名,vue-router 提供的导航守卫主要用来通过跳转或取消的方式守卫导航。这里有很多方式植入路由导航中:全局的,单个路由独享的,或者组件级的。
全局前置守卫
// 在路由跳转之前调用
router.beforeEach((to, from) => {
// ...
// 返回 false 以取消导航
return false
})
当一个导航触发时,全局前置守卫按照创建顺序调用。守卫是异步解析执行,此时导航在所有守卫 resolve 完之前一直处于等待中。
每个守卫方法接收两个参数:
均为 RouteLocationNormalized 对象: API 参考 | Vue Router (vuejs.org)
to
: 即将要进入的目标from
: 当前导航正要离开的路由
可以返回的值如下:
false
: 取消当前的导航。如果浏览器的 URL 改变了(可能是用户手动或者浏览器后退按钮),那么 URL 地址会重置到from
路由对应的地址。- 一个路由地址: 通过一个路由地址跳转到一个不同的地址,就像你调用
router.push()
一样,你可以设置诸如replace: true
或name: 'home'
之类的配置。当前的导航被中断,然后进行一个新的导航,就和from
一样。
// 在路由跳转之前 可判断用户是否登录
router.beforeEach(async (to, from) => {
if (
// 检查用户是否已登录
!isAuthenticated &&
// ❗️ 避免无限重定向
to.name !== 'Login'
) {
// 将用户重定向到登录页面
return { name: 'Login' }
}
})
如果遇到了意料之外的情况,可能会抛出一个 Error
。这会取消导航并且调用 router.onError()
注册过的回调。
如果什么都没有,undefined
或返回 true
,则导航是有效的,并调用下一个导航守卫
以上所有都同 async
函数 和 Promise 工作方式一样:
可选的第三个参数 next
确保 next
在任何给定的导航守卫中都被严格调用一次!!!!
// GOOD
router.beforeEach((to, from, next) => {
if (to.name !== 'Login' && !isAuthenticated) next({ name: 'Login' })
else next()
})
全局解析守卫
你可以用 router.beforeResolve
注册一个全局守卫。这和 router.beforeEach
类似,因为它在 每次导航时都会触发,但是确保在导航被确认之前,同时在所有组件内守卫和异步路由组件被解析之后,解析守卫就被正确调用。这里有一个例子,确保用户可以访问自定义 meta属性 requiresCamera
的路由:
// 不是很能理解这个钩子 等遇到相关需求的时候再看
router.beforeResolve(async to => {
if (to.meta.requiresCamera) {
try {
await askForCameraPermission()
} catch (error) {
if (error instanceof NotAllowedError) {
// ... 处理错误,然后取消导航
return false
} else {
// 意料之外的错误,取消导航并把错误传给全局处理器
throw error
}
}
}
})
全局后置钩子
你也可以注册全局后置钩子,然而和守卫不同的是,这些钩子不会接受 next
函数也不会改变导航本身:
router.afterEach((to, from) => {
alert(to.fullPath)
})
// 可选参数 failure 判断路由是否跳出
router.afterEach((to, from, failure) => {
if (!failure) sendToAnalytics(to.fullPath)
})
路由独享的守卫
const routes = [
{
path: '/users/:id',
component: UserDetails,
// 可在 配置时 直接给该路由配置单独的路由守卫
beforeEnter: (to, from) => {
// reject the navigation
return false
},
// 也可以使用数组的形式 依次访问
beforeEnter: [removeQueryParams, removeHash],
},
]
router link 与 view
以下内容 从官方文档CV 建议直接看文档
这部分都比较好理解
API 参考 | Vue Router (vuejs.org)
router-link参数
to
<!-- 使用URL跳转 -->
<router-link to="/home">Home</router-link>
<!-- 渲染结果 -->
<a href="/home">Home</a>
<!-- 使用 v-bind 的 JS 表达式 -->
<router-link :to="'/home'">Home</router-link>
<!-- 同上 -->
<!-- 对象配置 to -->
<router-link :to="{ path: '/home' }">Home</router-link>
<!-- 命名的路由 -->
<router-link :to="{ name: 'user', params: { userId: '123' }}">User</router-link>
<!-- 带查询参数,下面的结果为 `/register?plan=private` -->
<router-link :to="{ path: '/register', query: { plan: 'private' }}">
Register
</router-link>
replace
-
类型:
boolean
-
默认值:
false
-
详细内容:
设置
replace
属性的话,当点击时,会调用router.replace()
,而不是router.push()
,所以导航后不会留下历史记录。
<router-link to="/abc" replace></router-link>
active-class
-
类型:
string
-
默认值:
"router-link-active"
(或者全局linkActiveClass
) -
详细内容:
链接激活时,应用于渲染的
<a>
的 class。
custom
-
类型:
boolean
-
默认值:
false
-
详细内容:
<router-link>
是否应该将其内容包裹在<a>
元素中。在使用v-slot
创建自定义 RouterLink 时很有用。默认情况下,<router-link>
会将其内容包裹在<a>
元素中,即使使用v-slot
也是如此。传递自定义的
prop,可以去除这种行为。 -
例如:
<router-link to="/home" custom v-slot="{ navigate, href, route }"> <a :href="href" @click="navigate">{{ route.fullPath }}</a> </router-link>
渲染成
<a href="/home">/home</a>
。<router-link to="/home" v-slot="{ route }"> <span>{{ route.fullPath }}</span> </router-link>
渲染成
<a href="/home"><span>/home</span></a>
。
exact-active-class
-
类型:
string
-
默认值:
"router-link-exact-active"
(或者全局linkExactActiveClass
) -
详细内容:
链接精准激活时,应用于渲染的
<a>
的 class。
v-slot
可以将 渲染后的a标签包裹在内部
router-view参数
name
-
类型:
string
-
默认值:
"default"
-
详细内容:
如果
<router-view>
设置了name
,则会渲染对应的路由配置中components
下的相应组件。 -
详情见 compoents配置
route
(我直接看不懂这个 不理解)
-
类型:
RouteLocationNormalized
-
详细内容:
一个路由地址的所有组件都已被解析(如果所有组件都被懒加载),因此可以显示。
v-slot
<router-view>
暴露了一个 v-slot
API,主要使用 <transition>
和 <keep-alive>
组件来包裹你的路由组件。
示例:
<!-- Component为路由对应的组件 -->
<!-- route 为 route对象 可在官方文档查阅 -->
<router-view v-slot="{ Component, route }">
<transition :name="route.meta.transition || 'fade'" mode="out-in">
<keep-alive>
<suspense>
<template #default>
<component
:is="Component"
:key="route.meta.usePathKey ? route.path : undefined"
/>
</template>
<template #fallback> Loading... </template>
</suspense>
</keep-alive>
</transition>
</router-view>
在路径组件上使用转场,并对导航进行动画处理
单个路由过度
const routes = [
{
path: '/custom-transition',
component: PanelLeft,
meta: { transition: 'slide-left' },
},
{
path: '/other-transition',
component: PanelRight,
meta: { transition: 'slide-right' },
},
]
<router-view v-slot="{ Component, route }">
<!-- 使用任何自定义过渡和回退到 `fade` -->
<transition :name="route.meta.transition || 'fade'">
<component :is="Component" />
</transition>
</router-view>
强制在复用的视图之间进行过渡
Vue 可能会自动复用看起来相似的组件,从而忽略了任何过渡。幸运的是,可以添加key属性来强制过渡。这也允许你在相同路由上使用不同的参数触发过渡:
<router-view v-slot="{ Component, route }">
<transition name="fade">
<component :is="Component" :key="route.path" />
</transition>
</router-view>
keep-alive
vue中的keep-alive的用法详细讲解 - 知乎 (zhihu.com)
- 所以使用keep-alive就是保持组件活跃,不会被destroy销毁掉,就一直还活着,组件没有被销毁掉的话,组件上挂载的数据就还存在,所以状态就可以保留,所以,keep-alive就可以保持组件的状态。
<!-- 使用keep-alive包了一层,就可以缓存啦 -->
<keep-alive>
<router-view></router-view>
</keep-alive>
include属性
include 包含的意思。值为字符串或正则表达式或数组。只有组件的名称与include的值相同的才会被缓存,即指定哪些被缓存,可以指定多个被缓存。这里以字符串为例,指定多个组件缓存,语法是用逗号隔开。如下:
// 指定home组件和about组件被缓存
<keep-alive include="home,about" >
<router-view></router-view>
</keep-alive>
exclude属性
exclude相当于include的反义词,就是除了的意思,指定哪些组件不被缓存,用法和include类似,如下:
// 除了home组件和about组件别的都缓存,本例中就是只缓存detail组件
<keep-alive exclude="home,about" >
<router-view></router-view>
</keep-alive>