赞
踩
vue-router用法大全
使用了一段时间 Vue2 + Vuex + VueRouter + Element UI 开发之后
发现仅仅只用到了VueRouter的少数浅层功能 大部分高级功能都没有用到 决定看官方文档学习一下
官方文档是最好的学习笔记(●’◡’●)
API 参考 | Vue Router (vuejs.org)
参数 | 类型 | 默认值 | 可选值 | 描述 |
---|---|---|---|---|
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
//hash: 使用 URL hash 值来作路由。支持所有浏览器,包括不支持 HTML5 History Api 的浏览器。
//history: 依赖 HTML5 History API 和服务器配置。查看 HTML5 History 模式。
//abstract: 支持所有 JavaScript 运行环境,如 Node.js 服务器端。如果发现没有浏览器的 API,路由会自动强制进入这个模式。
使用前端路由,当切换到新路由时,想要页面滚到顶部,或者是保持原先的滚动位置,就像重新加载页面那样。 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) }) }
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
}
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 | 组件路由传参 |
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
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>
{
path:"BlogContent",
// 可以使用函数的方式进行懒加载
component: component: () => import('../views/MusicPlay')
// 也可直接 import后 在此处使用
component: ComponentObject
// 在项目开发中应用中不需要一开始就加载的路由组件请使用懒加载
// 路由的懒加载,通过函数的形式,可以让项目中哪些不许一开始就要加载的组件,加载到项目中去
// 只有浏览器跳转到当前路由时,该路由组件才会加载到项目中去
// 这样做的好处是减少不必要的加载降低应用加载速度和运行带宽
},
有时候想同时 (同级) 展示多个视图,而不是嵌套展示,例如创建一个布局,有 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>
// 可以使用路径重定向
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 } }
},
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' },]
我们称呼 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 },
}
}
})
是否严格匹配大小写
false:严格匹配
ture:大小写均可匹配
// 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],
},
]
以下内容 从官方文档CV 建议直接看文档
这部分都比较好理解
API 参考 | Vue Router (vuejs.org)
<!-- 使用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>
类型:boolean
默认值:false
详细内容:
设置 replace
属性的话,当点击时,会调用 router.replace()
,而不是 router.push()
,所以导航后不会留下历史记录。
<router-link to="/abc" replace></router-link>
类型:string
默认值:"router-link-active"
(或者全局 linkActiveClass
)
详细内容:
链接激活时,应用于渲染的 <a>
的 class。
类型: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>
。
类型:string
默认值:"router-link-exact-active"
(或者全局 linkExactActiveClass
)
详细内容:
链接精准激活时,应用于渲染的 <a>
的 class。
可以将 渲染后的a标签包裹在内部
类型:string
默认值:"default"
详细内容:
如果 <router-view>
设置了 name
,则会渲染对应的路由配置中 components
下的相应组件。
详情见 compoents配置
(我直接看不懂这个 不理解)
类型:RouteLocationNormalized
详细内容:
一个路由地址的所有组件都已被解析(如果所有组件都被懒加载),因此可以显示。
<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>
vue中的keep-alive的用法详细讲解 - 知乎 (zhihu.com)
<!-- 使用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>
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。