vue-router 基础
- 作用: 通过管理URL,实现URL和组件的对应和通过URL进行组件之间的切换
- 其他概念:
单页应用:加载单个HTML页面,并在用户与应用程序交互时,动态该页面
-
使用步骤:
-
安装模块:
npm install vue-router --save
-
引入模块:
import VueRouter from 'vue-router'
-
作为插件:
Vue.use(VueRoter)
-
创建路由实例对象:
new VueRouter({ // 匹配相关参数 })
-
注入vue选项参数:
new VueRouter({ router })
-
告诉路由渲染的位置:
-
引入组件,匹配组件URL:
<router-link v-bind:to="path"> 内容 </router-link>
具体页面代码:
import Vue from 'vue' // 1. 安装vue-router后引入vue-router模块 import Router from 'vue-router' import Index from '@/views/index' // 2. 作为插件 Vue.use(Router) // 3. 创建路由实例对象 export default new Router({ mode : 'history',// 历史模式 linkActiveClass: 'is-active', // 活动样式 scrollBehavior(to, from, savePosition){ // 点击浏览器的前进后退或切换导航时触发 console.log(to); // 要进入的目标对象 要去哪 console.log(from); // 离开的目标 从哪来 console.log(savePosition); // 记录滚动条位置,点击前进后退时触发 // if(savePosition){ // return savePosition; // 滚动条位置不是0时,即可保存位置 // }else{ // return {x:0,y:0} // } if(to.hash){ return { selector: to.hash } } }, routes: [ { path: '/', name: 'Index', component: Index } ] })
动态路由匹配
动态路径参数 以冒号开头
{ path:'/user/:id',component: User }
一个“路径参数”使用冒号
:
标记。当匹配到一个路由时,参数会被设置到this.$route.params
,可以在每个组件内使用。
也可以在一个路径张红设置多段“路径参数”,对应的值都会设置到$route.params
中- 捕获所有路由或404 Not found路由
{path: '*'}
当使用了一个通配符时,
$route.params
内会自动添加一个名为pathMath
参数。 -
编程式的导航
除了使用<router-link></router-link>
创建a标签来定义导航链接,还可以通过编写代码来实现。
router.push(location, onComplete?, onAbort?)
注意:在vue实例内部,可以通过$router
访问路由实例
想要导航到不同的URL,则使用router-push
方法。这个方法会向history栈添加一个新的记录
该方法的参数可以是一个字符串路径,或者一个描述地址的对象
// 字符串
router.push('home')
// 对象
router.push({ path: 'home' })
// 命名的路由
router.push({ name: 'user', params: { userId: '123'} })
// 带查询参数,变成 /register?plan=private
router.push({ path: 'register', query: { plan: 'private' } })
router.replace(location, onComplete?, onAbort?)
:替换掉当前的history记录
router.go(n)
在history记录中向前或者后退多少步,类似window.history.go(n)
命名视图
<router-view name='slider'></router-view>
路由视图<router-view>
一般的默认命名为default
,当想要匹配不同的视图时,便可以通过命名,找到相应的视图组件。name
值的匹配
## 重定向和别名 ``` const router = new VueRouter({ routes: [ {path: '/a', redirect: '/b'} ] }) ``` 或者是动态返回重定向目标:
const router = new VueRouter({
routes: [
{path:'/a',redirect: to =>{
// 方法接收 目标路由 作为参数
// return 重定向的 字符串路径/路径对象
}}
]
})
注意导航守卫并没有应用在跳转路由上,而仅仅应用在其目标上。
路由组件传参
在组件中使用
$route
会使之与其对应路由形成高度耦合,从而使组件只能在某些特定的URL上使用,限制了灵活性。
使用props
将组件和路由解耦:
取代与$route的高耦合
const User = {
template: '<div>User {{ $route.params.id }}</div>'
}
const router = new VueRouter({
routes: [
{ path: '/user/:id', component: User }
]
})
通过 props 解耦
const User = {
props: ['id'],
template: '<div>User {{ id }}</div>'
}
const router = new VueRouter({
routes: [
{ path: '/user/:id', component: User, props: true },
// 对于包含命名视图的路由,你必须分别为每个命名视图添加 `props` 选项:
{
path: '/user/:id',
components: { default: User, sidebar: Sidebar },
props: { default: true, sidebar: false }
}
]
})
三大模式
- 布尔模式
如果
props
被设置为true
,route.params
将会被设置为组件属性
- 对象模式
如果
props
是一个对象,它会被按原样设置为组件属性。当props
是静态的时候有用
- 函数模式
可以创建一个函数返回
props
。这样就可以将参数转换成另一种类型,将静态值与基于路由的值结合等。
尽可能保持props
函数为无状态的,因为它只会在路由发生变化时起作用。如果需要状态来定义props
,请使用包装组件,这样vue才可以对状态变化做出反应
导航守卫
组件内的守卫
const Foo = {
template: `...`,
beforeRouteEnter (to, from, next) {
// 在渲染该组件的对应路由被 confirm 前调用
// 不!能!获取组件实例 `this`
// 因为当守卫执行前,组件实例还没被创建
},
beforeRouteUpdate (to, from, next) {
// 在当前路由改变,但是该组件被复用时调用
// 举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候,
// 由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。
// 可以访问组件实例 `this`
},
beforeRouteLeave (to, from, next) {
// 导航离开该组件的对应路由时调用
// 可以访问组件实例 `this`
}
}
注意: beforeRouteEnter
守卫不能访问this
,因为守卫在导航确认前被调用,因此即将登场的新组件还没被创建。
不过可以通过一个回调next
来访问组件实例。在导航被确认的时候执行回调,并且把组件实例作为回调方法的参数:
beforeRouteEnter (to, from, next) {
next(vm => {
// 通过 `vm` 访问组件实例
})
}
注意: beforeRouteEnter
是支持给next
传递回调的唯一守卫。对于 beforeRouteUpdate 和 beforeRouteLeave 来说,this 已经可用了,所以不支持传递回调,因为没有必要了
beforeRouteUpdate (to, from, next) {
// just use `this`
this.name = to.params.name
next()
}
这个离开守卫通常用来禁止用户在还未保存修改前突然离开。该导航可以通过 next(false) 来取消。
beforeRouteLeave (to, from , next) {
const answer = window.confirm('Do you really want to leave? you have unsaved changes!')
if (answer) {
next()
} else {
next(false)
}
}
完整的导航解析流程
- 导航被触发
- 在失活的组件里调用离开守卫。
- 调用全局的
beforeEach
守卫 - 在重用的组件里调用
beforeRouteUpdate
- 在路由配置里调用
beforeEnter
- 解析异步路由组件
- 在被激活的组件里调用
beforeRouteEnter
- 调用全局的
beforeResolve
守卫 - 导航被确认
- 调用全局的
afterEach
钩子 - 触发DOM更新
- 用创建好的实例调用
beforeRouteEnter
守卫中传给next
的回调函数
路由元信息
一个路由匹配到的所有路由记录会暴露为$route
对象(还有在导航守卫中的路由对象)的$route.matched
数组。因此,我们需要遍历$route.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()
}
})
数据获取
- 导航完成之后获取:先完成导航,然后在接下来的组件生命周期钩子中获取数据。在数据获取期间显示“加载中”之类的指示。
- 导航完成之前获取:导航完成前,在路由进入的守卫中获取数据,在数据获取成功后执行导航。
导航完成后获取数据
马上导航和渲染组件,然后在组件的created
钩子中获取数据。获取数据期间会展示loading
状态,可以在不同视图间展示不同的loading
状态。