vue-router
简介
vue-router和vue.js是深度集成的,适用于单页面应用,传统的路由是用一些产链接来实现页面切换和跳转。而vue-router在单页面应用中,则是组件之间的切换,其本质就是:建立并管理url和对应组件之间的映射关系。
动态路由匹配
定义路由
const router = new Router({
routes: [
{
path: '/',
name: 'HelloWorld',
component: HelloWorld,
},
{
path: '/vue1',
name: 'vue1',
component: vue1
}
]
})
页面
<template>
<div>
<router-link :to="{name:'vue1',params:{data:111}}">去vue1</router-link>
</div>
</template>
点击
去vue1
跳转到http://localhost:8080/#/vue1
router-link
组件支持用户在具有路由功能能的应用中(点击)导航。 通过 to 属性指定目标地址,默认渲染成带有正确链接的 标签,可以通过配置 tag 属性生成别的标签.。另外,当目标路由成功激活时,链接元素自动设置一个表示激活的 CSS 类名。
比起写死的 <a href="...">
会好一些,理由如下:
<a href="...">
会好一些,理由如下:- 无论是
HTML5 history
模式还是hash
模式,它的表现行为一致,所以,当你要切换路由模式,或者在IE9
降级使用hash
模式,无须作任何变动。 - 在
HTML5 history
模式下,router-link
会守卫点击事件,让浏览器不再重新加载页面。 - 当你在
HTML5 history
模式下使用base
选项之后,所有的to
属性都不需要写 (基路径) 了。
跳转的页面接收路由参数
<template>
<div>
<button>{{$route.params.data}}</button>
</div>
</template>
$route.params.data
会输出111
响应路由参数的变化
当使用路由参数时,例如从
helloWorld/1
导航到helloWorld/2
,原来的组件实例会被复用。因为两个路由都渲染同个组件,比起销毁在创建,复用则显得更加高效,不过,这也意味着组建的生命周期钩子不会再被调用。
父组件
<template>
<div class="book">
<router-link :to="{ name:'vue1',params: { id: 1}}">跳转</router-link>
</div>
</template>
子组件
<template>
<div class="book-details">
<router-link :to="{ name:'vue1',params: { id: 2}}">自己跳自己</router-link>
</div>
</template>
<script>
export default {
watch:{
'$route'(to){
console.log(to,'监听路由')
}
},
}
</script>
还有一种方法
<template>
<div class="book-details">
<router-link :to="{ name:'vue1',params: { id: 2}}">自己跳自己</router-link>
</div>
</template>
<script>
export default {
beforeRouteUpdate(to, from, next){
console.log(to, from, next,'导航守卫')
next()
},
watch:{
'$route'(to){
console.log(to,'监听路由')
}
},
}
</script>
使用路由守卫
beforeRouteUpdate
,这里需要注意一定要加next()
捕获所有路由或404 Not found 路由
export default new Router({
routes: [
{
path: '/',
name: 'HelloWorld',
component: HelloWorld,
},
{
path:'*',
name:'vue2',
component:vue2
}
]
})
当使用通配符时,必须确保路由的顺序是正确的,也就是说含有通配符的路由应该放在最后。路由
path:'*'
通常用于客户端404错误。当我们随便输入一个urlhttp://localhost:8080/#/65446
,这时候就会匹配到404页面
高级匹配模式
vue-router使用
path-to-regexp
作为路径匹配引擎,所以很多高级的匹配模式,例如:可选的动态路径参数,匹配0个或多个,甚至是自定义正则匹配
举个例子
<template>
<div>
<router-link :to="{ name:'vue1',params:{data:true}}">跳转</router-link>
</div>
</template>
{
path: '/vue1/:data(\\d+)',
name: 'vue1',
component: vue1
}
点击跳转vueRouter会提示
[vue-router] missing param for named route "vue1": Expected "data" to match "\d+", but received "true"
匹配优先级
有时候,同一个路径可以匹配多个路由,此时,匹配的优先级就按照路由的定义顺序:谁先定义的,谁的优先级就最高
<template>
<div>
<router-link :to="{ name:'vue1'}">跳转</router-link>
</div>
</template>
// 路由
export default new Router({
routes: [
{
path: '/',
name: 'HelloWorld',
component: HelloWorld,
},
{
path:'/vue*',
name:'vue2',
component:vue2
},
{
path: '/vue*',
name: 'vue1',
component: vue1
},
]
})
当面代码中,点击跳转会跳转的
vue2
这个组件,vue2
写在vue1
前面,所有vue2
的优先级比vue1
高
嵌套路由
Vue会自带一个最顶层的出口,渲染最高级路由匹配到的组件。同样的,一个被渲染的组件同时可以包含自己的嵌套
组件
<template>
<div>
<router-link :to="{ name:'vue1'}">跳转</router-link>
<router-view></router-view>
</div>
</template>
路由
export default new Router({
routes: [
{
path: '/',
name: 'HelloWorld',
component: HelloWorld,
children:[
{
path:'/vue1',
name:'vue1',
component:vue1
}
]
},
]
})
注意如果要显示子组件的内容需要
<router-view></router-view>
接收
当我们访问http://localhost:8080/#/
的时候<router-view></router-view>
里面是没有内容的
解决办法
export default new Router({
routes: [
{
path: '/',
name: 'HelloWorld',
component: HelloWorld,
children:[
{
path:'',
component:vue2
},
{
path:'/vue1',
name:'vue1',
component:vue1
}
]
},
]
})
配置一个空的
path
,这时候访问http://localhost:8080/#/
,就会显示vue2
组件中的内容
编程式的导航
除了使用
创建 a
标签来定义导航连接,我们还可以借助router
的实例方法,通过编写代码来实现。
注意:在vue实例的内部,你可以通过$router访问路由实例。因此你可以调用this.$router.push()
。想要导航到不同的URL,则使用router.push方法。这个方法会向history
栈添加一个新的记录,所以当用户点击浏览器后退按钮时,则回到之前的URL。
- 声明式 :
- 编程式 : router.push()
<template>
<div class="book">
<router-link :to="{ name:'vue1',params: { id: 1}}">跳转</router-link>
</div>
</template>
<script>
export default {
methods:{
jump(){
// 字符串
this.$router.push('vue1')
// 对象
this.$router.push({path:'vue1'})
// 命名的路由
this.$router.push({name:'vue1',params:{userId:'123'}})
// 带查询参数
this.$router.push({path:'vue1',query:{userId:'123'}})
}
}
}
</script>
注意:如果提供了
path
,params会被忽略。
this.$router.push({name:'vue1',params:{userId:'123'}}) => userId:123
this.$router.push({path:'vue1',params:{userId:'123'}}) 不生效
// 正确写法
this.$router.push({path:'vue1',query:{userId:'123'}})
子组件接收也需要使用 $route.query
router.go()
这个方法的参数是一个证书,意思实在
history
记录中向前或者后退多少步,类似 window.history.go(n)
// 在浏览器记录中前进一步,等同于 history.forward()
router.go(1)
// 后退一步记录,等同于 history.back()
router.go(-1)
// 前进 3 步记录
router.go(3)
命名路由
有时候,通过一个名称来标识一个路由显得更方便一些,特别是在链接一个路由,或者是执行一些跳转的时候。你可以在创建 Router 实例的时候,在 routes 配置中给某个路由设置名称。
路由
export default new Router({
routes: [
{
path: '/',
name: 'HelloWorld',
component: HelloWorld
},
{
path: '/vue1aa',
name: 'vue1',
component: vue1
},
]
})
用法
<router-link :to="{ name: 'vue1'}">跳转</router-link>
或者
this.$router.push({name:'vue1'})
嵌套命名视图
export default new Router({
routes: [
{
path: '/',
name: 'HelloWorld',
component: HelloWorld,
children:[
{
path: 'vue1',
name: 'vue1',
components: {
default: vue3,
animal: vue1
}
},
{
path: 'vue2',
name: 'vue2',
component: vue2
}
]
}
]
})
当跳转到
http://localhost:8080/#/vue2
只会显示一个vue2
组件,当跳转到http://localhost:8080/#/vue1
会显示vue1,vu3
两个组件
重定向和别名
{
path: '/vue1',
name: 'vue1',
component: vue1,
redirect:'/vue1/vue2',
children:[
{
path: 'vue2',
name: 'vue2',
component: vue2
}
]
}
当我们访问
http://localhost:8080/#/vue1
会重定向到http://localhost:8080/#/vue1/vue2
重定向的路由也可以是一个命名路由
{
path: '/vue1',
name: 'vue1',
component: vue1,
redirect:{name:'vue2'},
children:[
{
path: 'vue2',
name: 'vue2',
component: vue2
}
]
}
甚至是一个方法返回重定向目标
{
path: '/Fruits',
redirect: to => {
// 方法接收 目标路由 作为参数
// return 重定向的 字符串路径/路径对象
}
}
别名
{
path: '/vue1',
name: 'vue1',
component: vue1,
alias: '/haha'
}
当我们访问的
http://localhost:8080/#/haha
实际访问的是http://localhost:8080/#/vue1
路由组件传参
组件
<template>
<div>
<router-link :to="{ name: 'vue1',params:{id:111222}}">跳转</router-link>
</div>
</template>
<template>
<div>
{{id}}
</div>
</template>
<script>
export default {
props:['id'],
}
路由
{
path: '/vue1/:id',
name: 'vue1',
component: vue1,
props:true
}
布尔模式
在路由配置中设置 props: true 时默认将 $route.params 数据传给组件,组件需要通过自身的 props 属性取出 params 中的属性
对象模式
如果 props 是一个对象,其下所有属性均会被传入组件。需要注意的是当 props 必须是是静态的
路由
{
path: '/vue1/:id',
name: 'vue1',
component: vue1,
props:{
name:'hah',
age:11
}
}
<template>
<div>
<router-link :to="{ name: 'vue1'}">跳转</router-link>
</div>
</template>
<template>
<div>
{{name}} {{age}}
</div>
</template>
<script>
export default {
props:['name','age'],
}
</script>
函数模式
{
path: '/vue1',
name: 'vue1',
component: vue1,
props:()=>({name:'小明'})
}
<template>
<div>
{{name}}
</div>
</template>
<script>
export default {
props:['name'],
}
</script>
HTML5 History 模式
vue-fouter
默认 hash 模式 —— 使用 URL 的 hash 来模拟一个完整的 URL,于是当 URL 改变时,页面不会重新加载。如果不想要很丑的 hash,我们可以用路由的 history 模式,这种模式充分利用 history.pushState API 来完成 URL 跳转而无须重新加载页面
路由
export default new Router({
mode: 'history',
routes: [
{
path: '/',
name: 'HelloWorld',
component: HelloWorld,
},
{
path: '/vue1',
name: 'vue1',
component: vue1,
props:()=>({name:'小明'})
}
]
})
来看一下用之前和用之后的地址
// hash
http://localhost:8080/#/
// history
http://localhost:8080/