vue-router

554 阅读3分钟

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'}})

如果有了pathparams会被忽略。

正确写法

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个路由导航守卫:

  • beforeRouteEnter
  • beforeRouteUpdate
  • beforeRouteLeave
<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()
    }
})

获取数据

  • 导航完成之后获取:先完成导航,然后再组件生命周期中获取数据,在数据获取期间显示加载中

  • 导航完成之前获取:导航完成之前,在路由进入的守卫中获取数据,在数据获取成功后执行导航