1.路由基本结构
2.router-link
3.命名路由
4.路由参数规则
5.重定向和别名
6.$route 和 $router的区别
7.多视图
8.监听路由
9.导航守卫
10. 路由懒加载
路由基本结构
1.容器
<router-view></router-view>
2.路由表
let router=new VueRouter({
routes: [
{path, component},
{path, component},
{path, component},
...
]
});
3.添加到vm对象
new Vue({
el, data, ...,
router: router
})
router-link
编译完之后就是a标签。主要通过to
属性来进行路由跳转
<router-link class="nav" :to="{name: 'news', params: {id: 98}}">页面1</router-link>
<router-link class="nav" to="/b">页面2</router-link>
<router-link class="nav" to="/c" tag="div">页面3</router-link>
tag
可以将默认的a
标签改为你指定的标签,比如div
router-link-active
是router-link
当前的选中自带class
名称,自己可以通过这个class
改变成你想要的效果。
router-link 也是遵守下面的路由参数规则
命名路由
对路由设置name
属性,为了方便路由的跳转,如果单纯的通过path
跳转,一旦path
的值过长,或者路由嵌套很深,会显的很乱维护也比较麻烦。
name
属性是可选的。
<router-link class="nav" :to="{name: 'news'}">页面1</router-link>
routes: [
{
path: '/news',
name: 'news', // look at here
component: {
template: '<div>新闻:{{$route.params.id}}</div>'
}
}
命名路由跳转
//常规
<router-link to="/xxx/xxx">
//命名路由跳转
<router-link class="nav" :to="{name: 'news', params: {id: 98}}">页面1</router-link>
路由可以重叠
当多个路由同时匹配到了,那么谁写在最前面就匹配谁的。
routes: [
{
path: '/news/aaa/',
component: {
template: '<div>新闻2</div>'
}
},
{
path: '/news/:id/',
component: {
template: '<div>新闻:{{$route.params.id}}</div>'
}
}
如果路由输入为/news/aaa
上面的结果会匹配第一个 显示为新闻2。
路由参数规则
路由可以通过name,path,params,query
来进行参数的传递以及路由的跳转。那么应该如何合理的使用这么参数呢?
// 字符串
router.push('home')
// 对象
router.push({ path: '/home' })
// 命名的路由
router.push({ name: 'user', params: { userId: '123' }})
// 带查询参数,变成 /register?plan=private
router.push({ path: '/register', query: { plan: 'private' }})
如果提供了 path
,params
会被忽略(因为path
是死路经,params
是动态路径,query
只是路径后的参数),上述例子中的 query
并不属于这种情况。
所以一般我们写路由的时候可以通过两种方式传参:
- router.push({ path: ‘/register’, query: { plan: ‘private’ }}) (path +query) //register?plan=private
- router.push({ name: ‘user’, params: { userId: ‘123’ }}) (name+params)// user/123
重定向和别名
重定向
重定向也是通过 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 重定向的 字符串路径/路径对象
}}
]
})
注意导航守卫
并没有应用在跳转路由上
,而仅仅应用在其目标上
。在下面这个例子中,为 /a
路由添加一个 beforeEach
或 beforeLeave
守卫并不会有任何效果。
别名
“重定向”的意思是,当用户访问 /a时,URL 将会被替换成 /b,然后匹配路由为 /b,那么“别名”又是什么呢?
/a 的别名是 /b,意味着,当用户访问 /b 时,URL 会保持为 /b,但是路由匹配则为 /a,就像用户访问 /a 一样。
const router = new VueRouter({
routes: [
{ path: '/a', component: A, alias: '/b' }
]
})
“别名”的功能让你可以自由地将 UI 结构映射到任意的 URL,而不是受限于配置的嵌套路由结构。
$route 和 $router的区别
当前路由信息:$route
$route.path
:字符串,等于当前路由对象的路径,会被解析为绝对路径,如 “/home/news” 。
$route.params
:对象,包含路由中的动态片段和全匹配片段的键值对。
$route.query
:对象,包含路由中查询参数的键值对。例如,对于 /home/news/detail/01?favorite=yes ,会得到$route.query.favorite = ‘yes’ 。
$route.router
:路由规则所属的路由器(以及其所属的组件)。
$route.matched
:数组,包含当前匹配的路径中所包含的所有片段所对应的配置参数对象。
$route.name
:当前路径的名字,如果没有使用具名路径,则名字为空。
操作路由:$router
this.$router.push( string|object);
fn1(){
this.$router.push('/news/19'); string
this.$router.replace({name: 'news', params: {id: Math.random()}}); object
},
history
其实是一个栈,所以路由需要push/replace来操作这个栈。
push
(string|object) 入栈
replace
(string|object) 替换最后一个历史纪录(当前)
go
(int) 就是前进后退
多视图
<div id="div1">
<router-link to="/">首页</router-link>
<router-link to="/news">新闻</router-link>
<!--1.路由容器-->
<router-view name="header"></router-view>
<router-view></router-view>
<router-view name="footer"></router-view>
</div>
//components 多个s
let router=new VueRouter({
routes: [
{
path: '/',
name: 'index',
components: {
default: indexCmp,
header: headerCmp,
footer: footerCmp
}
},
{
path: '/news',
name: 'news',
components: {
default: newsCmp,
header: headerCmp,
footer: footerCmp
}
}
]
});
监听路由
1.watch 简单——只能看不能干预
watch: {
$route(value, old_value){
console.log(value, old_value);
}
}
2.路由守卫 ---- 可以阻止路由的跳转 也能控制。
导航守卫
1. 全局守卫
2. 单个路由守卫
3. 组件内守卫
正如其名,vue-router
提供的导航守卫主要用来通过跳转或取消的方式守卫导航。有多种机会植入路由导航过程中:全局的, 单个路由独享的, 或者组件级的。
记住参数或查询的改变并不会触发进入/离开的导航守卫。你可以通过观察 $route
对象来应对这些变化,或使用 beforeRouteUpdate
的组件内守卫。
全局前置守卫
你可以使用 router.beforeEach
注册一个全局前置守卫:
const router = new VueRouter({ ... })
router.beforeEach((to, from, next) => {
// ...
})
当一个导航触发时,全局前置守卫按照创建顺序调用。守卫是异步解析执行,此时导航在所有守卫 resolve 完之前一直处于 等待中。
每个守卫方法接收三个参数:
to: Route: 即将要进入的目标 路由对象
from: Route: 当前导航正要离开的路由
next: Function: 一定要调用该方法来 resolve 这个钩子。执行效果依赖 next 方法的调用参数。
-
next(): 进行管道中的下一个钩子。如果全部钩子执行完了,则导航的状态就是 confirmed (确认的)。
-
next(false): 中断当前的导航。如果浏览器的 URL 改变了 (可能是用户手动或者浏览器后退按钮),那么 URL 地址会重置到 from 路由对应的地址。
-
next(’/’) 或者 next({ path: ‘/’ }): 跳转到一个不同的地址。当前的导航被中断,然后进行一个新的导航。你可以向 next 传递任意位置对象,且允许设置诸如 replace: true、name: ‘home’ 之类的选项以及任何用在 router-link 的 to prop 或 router.push 中的选项。
-
next(error): (2.4.0+) 如果传入 next 的参数是一个 Error 实例,则导航会被终止且该错误会被传递给 router.onError() 注册过的回调。
确保要调用 next 方法,否则钩子就不会被 resolved。
全局后置钩子
你也可以注册全局后置钩子,然而和守卫不同的是,这些钩子不会接受 next
函数也不会改变导航本身:
router.afterEach((to, from) => {
// ...
})
路由独享的守卫
你可以在路由配置上直接定义 beforeEnter
守卫:
const router = new VueRouter({
routes: [
{
path: '/foo',
component: Foo,
beforeEnter: (to, from, next) => {
// ...
}
}
]
})
这些守卫与全局前置守卫的方法参数是一样的。
组件内的守卫
最后,你可以在路由组件内直接定义以下路由导航守卫:
- beforeRouteEnter
- beforeRouteUpdate (2.2 新增)
- beforeRouteLeave
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
守卫 (2.2+)。 - 在路由配置里调用
beforeEnter
。 - 解析异步路由组件。
- 在被激活的组件里调用
beforeRouteEnter
。 - 调用全局的
beforeResolve
守卫 (2.5+)。 - 导航被确认。
- 调用全局的
afterEach
钩子。 - 触发
DOM
更新。 - 用创建好的实例调用
beforeRouteEnter
守卫中传给 next 的回调函数。
整合所有的守卫:
全局的前置守卫: beforeEach beforeResolve
全局的后置钩子: afterEach
(钩子函数 这里没有 next
)
路由独享的守卫: beforeEnter
组件内的守卫: beforeRouterEnter
、beforeRouterUpdate
、beforeRouteLeave
路由懒加载
当打包构建应用时,JavaScript 包会变得非常大,影响页面加载。如果我们能把不同路由对应的组件分割成不同的代码块,然后当路由被访问的时候才加载对应组件,这样就更加高效了。
结合 Vue 的异步组件和 Webpack 的代码分割功能,轻松实现路由组件的懒加载。
首先,可以将异步组件定义为返回一个 Promise 的工厂函数 (该函数返回的 Promise 应该 resolve 组件本身):
const Foo = () => Promise.resolve({ /* 组件定义对象 */ })
第二,在 Webpack 2 中,我们可以使用动态 import语法来定义代码分块点 (split point)
import('./Foo.vue') // 返回 Promise
如果您使用的是 Babel,你将需要添加 syntax-dynamic-import 插件,才能使 Babel 可以正确地解析语法。
结合这两者,这就是如何定义一个能够被 Webpack 自动代码分割的异步组件。
const Foo = () => import('./Foo.vue')
在路由配置中什么都不需要改变,只需要像往常一样使用 Foo:
const router = new VueRouter({
routes: [
{ path: '/foo', component: Foo }
]
})
可在路由中简写
{
path:'/foo',
name:'foo',
component: () => import('@/components/foo')
}
把组件按组分块
有时候我们想把某个路由下的所有组件都打包在同个异步块 (chunk) 中。只需要使用 命名 chunk,一个特殊的注释语法来提供 chunk name (需要 Webpack > 2.4)。
const Foo = () => import(/* webpackChunkName: "group-foo" */ './Foo.vue')
const Bar = () => import(/* webpackChunkName: "group-foo" */ './Bar.vue')
const Baz = () => import(/* webpackChunkName: "group-foo" */ './Baz.vue')
Webpack 会将任何一个异步模块与相同的块名称组合到相同的异步块中。
/* webpackChunkName: “group-foo” */ 是打包后文件名称,后面是文件路径。
‘./Foo.vue’ 是文件路径。
(可配置或者不配置)在build目录下找到webpack.prod.conf.js文件,将output修改为
output: {
path: config.build.assetsRoot,
filename: utils.assetsPath('js/[name].[chunkhash].js'),//文件格式,文件名.文件哈希
chunkFilename: utils.assetsPath('js/[name].[chunkhash].js')//文件切割后的文件名称。这里的name对应的就是路由中引入文件时候的webpackChunkName
}
还有一种形式:
也是实现懒加载的方法。
vue-router相关的内容就先介绍到这里了,希望对您有所帮助~。