vueRouter
安装好vue之后,我们要做的就是,将组件映射到路由上,然后告诉vueRouter在哪里渲染他们
//导入路由
import VueRouter from 'cue-router'
//使用路由
Vue.use(VueRouter)
// 挂载到实例
new Vue({
router
})
// 声明一个VueRouter实例
let router = new VueRouter({
routes
})
// vueRouter routes配置
const routes =[
{
path:'/',
component:Home
}
]
安装好之后会VueRouter自带两个组件<router-link>,<router-view>
<router-link>:传入to属性指定连接,默认渲染成一个a标签
<router-view>:路由匹配到的组件渲染在这里
路由注入之后,在任何组件内可以通过:
- this.$router访问路由器
- this.$route访问当前路由
动态路由匹配
const routes = [
{
path:'/user/:id',
component:User
children:[
{
path:'post/:post_id',
component:Post
}
]
}
]
// User.vue
{{$route.params.id}}
{{$route.params.post_id}}
响应路由参数的变化
复用组件时,路由参数变化了,可以用watch来监控$route对象:
watch:{
'$route'(to,from){
}
}
也可以使用beforeRouteUpdate
beforeRouteUpdate(to,from,next){
}
捕获所有路由或404
*: 可以匹配所有路径
post-*:匹配以/post-开头的任意路径
使用通配符,$route。params会自动添加一个pathMatch参数,存储被匹配的部分
const route = [
{
path:'/',
component:Home
},
{
path:'*',
component:Notfound
}
]
匹配优先级
按照路由定义的顺序,谁先定义的,谁的优先级就最高
嵌套路由
路径配置中增加children:[]
以/开头的嵌套路径会被当做根路径,所以在嵌套组件中无需设置嵌套路径
如果想访问/user/profile,User的出口不会渲染任何东西,因为没有匹配到子路由,
如果想渲染点什么可以提供一个空的子路由
const routes = [
{
path:'/',
component:Home,
},
{
path:'/about',
component:About,
},
{
path:'user',
component:User,
children:[
{
path:'',
component:UserHome
},
{
path:'profile',
component:Profile
},
{
path:'post',
compoent:Post
}
]
}
]
编程式导航
我们可以用<router-link :to="...">的写法,也可以用编程式的写法
router.push('...')
$router.push('home')
$router.push({path:'home'})
$router.push({name:'user',params:{userId:'123'}})
$router.push({path:'register',query:{plan:'private'}})
如果有了path,params会被忽略。
正确写法
const userId = '123';
$router.push({name:'user',params:{userId}}) ///user/123
$router/push({path:`user/${userID}`})
$router.push({path:'/user',params:{userId}}) // /user
如果目的地和当前路由相同,只有参数发生了变化。你需要使用beforeRouteUpdate来响应这个变化
- $router.push()
- $router.replace()
- $router.go()
命名路由
就可以给路由配置加一个name属性
const routes = [
{
name:'/user/:userId',
name:'user',
component:user
}
]
<router-link :to="{name:'user',params:{userId:123}}">User</router-link>
this.$router.push({name:'user',params:{userId:123}})
两种写法一致
命名视图
同时同级展示多个视图,而不是嵌套展示; 如sidebar,main,你可以在界面中拥有多个单独命名的视图,而不是只有一个单独的出口。
<router-view class="view one"></router-view>
<router-view class="view two" name="a"></router-view>
<router-view class="view three" name="b"></router-view>
const routes = [
{
path:'/',
component:{
default:Foo,
a:Bar,
b:Baz
}
}
]
给<router-view>一个name属性
路由配置component里面可以配置多个组件component:{default:Home,a:User,b:About}
嵌套命名视图
还可以使用命名视图创建嵌套视图的复杂布局
// userSetting
<div>
<h1>User Setting</h1>
<NavBar/>
<router-view/>
<router-view name=helper"/>
</div>
// router
{
path:'/settings',
component:UserSettings,
children:[
{
path:'emails',
component:UserEmailsSubscriptions
},
{
path:'profile',
components:{
default:UserProfile,
helper:UserProfilePreview
}
}
]
}
重定向和别名
重定向 redirect
“重定向”的意思是,当用户访问 /a时,URL 将会被替换成 /b,然后匹配路由为 /b
重定向就是从一个地址跳到另一个地址,路由路径会跳到重新定义的地址,匹配新的路由组件
const routes = [
{
path:'/a',
// redirect:'/b',
// redirect:{name:'foo'}
redirect:(to)=>{
return '/b'
}
}
]
别名 alias
别名就是当用户访问/b,url会变成/b,但是路由会匹配/a,就象用户访问/a一样
const router = new VueRouter({
routes:[
{
path:'/a',
component:A,
alias:'/b'
}
]
})
别名可以让你自由的将UI映射到任意URL,而不受限于配置的嵌套路由结构
路由组件传参
如果在组件中使用$route会使之于其对应路由形成高度耦合,从而使组件只能在某些特定的URL上使用,限制了灵活性
<div>
User {{$route.params.id}}
</div>
const routes = [
{
path:'/user/:id',
component:User
}
]
可以通过props解耦
<div>
User{{id}}
</div>
<sciript>
export default{
props:['id']
}
</script>
const routes = [
{
path:'/user/:id',
component:User,
props:true
},
{
path:'/user/:id',
components:{
default:User,
sidebar:Sidebar
},
props:{
default:true,
sidebar:false
}
}
]
布尔对象
如果props被设置为true,route.params将会被设置为组件属性
对象模式
如果props是一个对象,它会按原样设置为组件属性,当props是静态的时候有用。
const router = new VueRouter({
routes:[
{
path:'、promotion/from-newsletter',
component:Promotion,
props:{
newsletterProp:false
}
}
]
})
函数模式
还可以创建一个函数返回props,这样你就可以将参数转换成另外一种类型,将静态值于基于路由的值结合
const router = new VueRouter({
routes:[
{
path:'/search',
component:Searech,
props:(route)=>({
query:route.query.q
})
}
]
})
URL/search?q=vue会将{query:'vue'}作为属性传递给SearchUser组件
导航守卫
全局
vue-router提供的导航守卫主要用来通过跳转或取消的方式守卫导航。
有多种机会植入路由导航的过程中:全局的,单个路由独享的,或者组件级的。
参数或查询的改变并不会触发进入/离开的导航守卫 ,你可以通过wacth$route对象或者使用beforeRouteUpdate的组件内守卫
全局前置守卫 router.beforeEach
当触发一个导航时,全局前置守卫按照创建顺序调用。 守卫是异步执行的,此时导航在所有守卫resolve完之前一直处于等待态。
const router = new VueRouter({})
router.beforeEach((to,from,next)=>{
//to:将要进入的目标路由对象
// from:当前导航正要离开的路由
// next:一定要调用该方法来resolve这个钩子
})
全局解析守卫 router.beforeResolve
router.beforeResolve:注一个全局守卫、
和router.beforeEach类型
区别就是在导航被确认之前,同时在所有组件内守卫和异步路由组件被解析之后,解析守卫被调用
全局后置钩子 router.afterEach
router.afterEach((to,from)=>{})
路由独享的守卫 beforeEnter
路由独享的就是在路由配置的时候可以直接声明beforeEnter
const router = new VueRouter({
routes:[
{
path:'/foo',
component:Foo,
beforeEnter:(to,from,next)=>{}
}
]
})
组件内的守卫
路由组件内可以直接定义下面3个路由导航守卫:
beforeRouteEnterbeforeRouteUpdatebeforeRouteLeave
<script>
export default{
data(){},
watch:{},
beforeRouteEnter(to,from,next){
//在渲染该组件的对应路由被cofirm前调用
// 不能获取组件实例`this`
// 因为当前守卫执行,组件实例还没被创建
// next(vm=>{ // 通过vm可以访问组件实例})
},
beforeRouteUpdate(to,from,next){
//在当前路由改变,但是该组件被复用时调用 /user/1 到/user/2 组件被复用这时调用
// 可以访问组件实例`this`
},
beforeRouteLeave(to,from,next){
// 导航离开该组件的对应路由时调用
// 可以访问组件实例`this`
// 这个离开守卫通常用来禁止用户在还未保存修改前突然离开,通过next(false)取消
}
}
</script>
完整的导航解析流程
- 1.导航被激活
- 2.在失活的组件里调用离开守卫
- 3.调用全局的
beforeEach守卫 - 4.在重用的组件里调用
beforeRouteUpdate - 5.在路由配置里调用
beforeEnter - 6.解析异步路由组件
- 7.在被激活的组件里调用
beforeRouteEnter - 8.调用全局的
beforeEach - 9.导航被确认
- 10.调用全局的
afterEach - 11.触发DOM更新
- 12.用创建好的实例调用
beforeRouteEnter中传给next的回调函数
路由元信息
const router = new VueRouter({
routes:[
{
path:'/foo',
component:Foo,
chiuldren:[
{
path:'bar',
component:Bar,
meta:{
requiresAuth:true
}
}
]
}
]
})
router.beforeEach((to,from,next)=>{
if(to.matched.some(record => record.meta.requiresAuth)){
if(!auth.loggedIn()){
next({
path:'/login',
query:{redirect:to.fullPath}
})
}else{
next()
}
}else{
next()
}
})
获取数据
-
导航完成之后获取:先完成导航,然后再组件生命周期中获取数据,在数据获取期间显示加载中
-
导航完成之前获取:导航完成之前,在路由进入的守卫中获取数据,在数据获取成功后执行导航