vue路由的高级应用

246 阅读4分钟

$route$router

每个注册过的路由都有自己的 $route 属性,里面包含query参数、params参数、meta元信息等属性。

1647909929(1).jpg

所有路由共用一个 $router,就像一个路由器管理所有的路由接口。

$router 包括一些路由信息,比如:当前所在的路由 this.$router.currentRoute,已配置好的路由 this.$router.options.routes

1647910101(1).jpg

$router 提供了一些方法,比如 push跳转页面 addRoute增加路由。

1647910178(1).jpg

路由的query传参

query传参类似于get请求,将参数信息携带在url中,可以通过 this.$route.query 获取。

<!-- 跳转路由并携带query参数,固定参数 -->
<router-link to="/login?user=admin" >登录</router-link>
<!-- 跳转路由并携带query参数,动态参数 -->
<router-link :to="`/login?user=${user}`" >登录</router-link>
<!-- 跳转路由并携带query参数,对象写法 -->
<!-- 使用query传参,通过path或name跳转都可 -->
<router-link :to="{
    path:'/login',
    // name:'login',
    query:{
        user:user
    }
}" >登录</router-link>
data(){
    return {
        user:'admin'
    }
}

路由的params传参

通过params传递的参数可以通过 this.$route.params 获取。

<!-- 跳转路由并携带params参数,固定参数 -->
<router-link to="/login/admin" >登录</router-link>
<!-- 跳转路由并携带params参数,动态参数 -->
<router-link :to="`/login/${user}`" >登录</router-link>
<!-- 跳转路由并携带params参数,对象写法 -->
<!-- 使用params传参,只能通过name跳转 -->
<router-link :to="{
    name:'login',
    params:{
        user:user
    }
}" >登录</router-link>
data(){
    return {
        user:'admin'
    }
}

使用params传参,在配置路由时需要在path路径后加上‘/:user’,声明接收params参数,可传递多个参数。

const routes = [
  {
    path:'/login/:user', // 使用占位符声明接收params参数
    name:'login',
    component:()=>import('../views/LoginView.vue')
  }
  ]

当没有设置动态路由时,如果通过字符串路径跳转并使用params传参,浏览器会找不到对应的页面,如果通过一个描述地址的对象路径跳转并使用params传参,只能在第一次进入页面时可以通过 this.$route.params 获取参数,刷新后将无法获取,此时可以在第一次进入页面时使用本地缓存。

    created(){
      if(this.$route.params.id){
        localStorage.id = this.$route.params.id
      }
      let id = this.$route.params.id || localStorage.id
      console.log(id);
    }

路由Props配置

当传递多个参数时,可以通过 props 配置统一接收。

const routes = [
  {
    path:'/login/:user/:id', // 使用占位符声明接收params参数
    name:'login',
    component:()=>import('../views/LoginView.vue'),
    // props的第一种写法,值为对象,该对象中的所有key-value都会以props的形式传给LoginView组件
    // 对象写法使用较少,因为传递的是固定的数据
    // props:{user:'admin',id:001}
    
    // props的第二种写法,值为布尔值
    // 若布尔值为真,就会把该路由组件收到的所有params参数,以props的形式传给LoginView组件
    // props:true
    
    // props的第三种写法,值为函数,可以接收$route参数
    props($route){
       return {user:$route.query.user,id:$route.query.id}
    }
    // 连续解构赋值写法,缺点是语义化不明确
    // props({query:{user,id}}){
    //    return {user,id}
    // }
  }
  ]

LoginView 组件通过props接收。

export default {
    name:'LoginView',
    props:['user','id']
}

手动添加路由与子路由

this.$route 提供了 addRoute 方法可以添加路由或给路由添加子路由。

export default {
    name:'LoginView',
    methods:{
        // 添加一级路由vip
        addR(){
          this.$router.addRoute({
            path: '/vip',
            name: 'vip',
            /* 路径使用@表示src的方式实现 */
            /* 或者在本页面 使用./views/VipView.vue 的方式 获取页面*/
            component: () => import('@/views/VipView.vue')
          })
          console.log(this.$router)
        },
        /* 给about加上子路由 */
        addR2(){
          /* 添加子路由的时候需要第一个参数是主路由的name值 */
          this.$router.addRoute('about',{
            path:'aboutchild2',
            name:'aboutchild2',
            component: () => import('@/views/AboutChild2.vue'),
          })
          /* this.$router.currentRout表示当前所在的路由 */
          console.log(this.$router.currentRoute)
        }
    }
}

编程式路由导航(跳转和解决报错)

this.$route 提供了 pushreplacegobackforward 五种跳转路由的方法。

push 方法会向 history 栈添加一个新的记录,所以,当用户点击浏览器后退按钮时,会回到之前的 URL。 replace 方法在导航时不会向 history 添加新记录,它会替换当前的 URL。 push 方法和replace 方法参数可以是一个字符串路径,或者一个描述地址的对象。

go 方法采用一个整数作为参数,表示在历史堆栈中前进或后退多少步,类似于 window.history.go(n)

export default {
    name:'LoginView',
    methods:{
        tiaozhuan(){
            // push跳转会增加浏览历史记录,可以通过浏览器的后退按钮返回上一个网页
            // this.$router.push('/about')
            // this.$router.push({name:'about'})
             
            // replace跳转会替换当前网页的浏览历史记录,不能通过浏览器的后退按钮返回上一个网页
            // 在 routeLink 标签中添加replace指令就可以使用replace跳转模式
            // this.$router.replace('/about')
            
            // go跳转采用一个整数作为参数,表示在历史堆栈中前进或后退多少步,类似于window.history.go(n)。
            // 返回上一页后退()
            // this.$router.back();
            // this.$router.go(-1)
            // 刷新
            // this.$router.go(0)
            // 去下一页(前进)
            // this.$router.forward();
            // this.$router.go(1)
        }
    }
}

this.$router 提供的跳转方法只能跳转一次,跳转多次会报错,解决方法:在配置路由的 index.js 中添加如下代码。

const VueRouterPush = VueRouter.prototype.push
VueRouter.prototype.push = function push (to) {
  return VueRouterPush.call(this, to).catch(err => err)
}

设置路由钩子

守卫可接收参数触发时间
全局前置守卫beforeEachto,from,next当一个导航触发时,全局前置守卫按照创建顺序调用
全局后置守卫afterEachto,from导航被确认后
路由独享守卫beforEnterto,from,next只在进入路由时触发
组件内进入路由守卫beforeRouteEnterto,from,next在渲染该组件的对应路由被验证前调用,不能获取组件实例 this,可以通过传一个回调(vm形参)给 next 来访问组件实例
组件内路由更新守卫beforeRouteUpdateto,from,next在当前路由改变,但是该组件被复用时调用,举例来说,对于一个带有动态参数的路径 /users/:id,在 /users/1/users/2 之间跳转的时候;可以获取组件实例 this
组件内离开路由守卫beforeRouteLeaveto,from,next在导航离开渲染该组件的对应路由时调用,可以获取组件实例 this

路由元信息

我们在配置路由时,可以通过接收属性对象的 meta 属性来附加任意信息到路由上,如过渡名称、谁可以访问路由等,它可以在路由地址和导航守卫上都被访问到。

const routes = [
  {
    path: '/posts',
    component: PostsLayout,
    children: [
      {
        path: 'new',
        component: PostsNew,
        // 只有经过身份验证的用户才能创建帖子
        meta: { requiresAuth: true }
      },
      {
        path: ':id',
        component: PostsDetail
        // 任何人都可以阅读文章
        meta: { requiresAuth: false }
      }
    ]
  }
]

缓存路由组件

当路由路径发生变化时,旧的路由路径对应的路由组件会被销毁,新的路由路径对应的路由组件会被创建,与此同时,旧的路由路径对应的路由组件中的一些表单元素信息就会丢失,我们可以通过缓存路由组件来暂时保存这些信息。

     <!-- 使用<keep-alive></keep-alive>标签包裹组件展示区域 -->
     <!-- keep-alive标签内没有includes属性时,在展示区域内展示的所有组件都将被缓存 -->
     <!-- 想缓存的组件只有一个时,includes属性值直接写组件名即可 -->
     <!-- 组件名是组件的script导出的name,不是路由的name -->
     <!-- 想缓存的组件有有个时,includes属性值动态绑定一个数组,数组的每一项为想缓存的组件名 -->
     <keep-alive includes="news">
          <router-view/>
     </keep-alive>
     <keep-alive :includes="['news','message']">
          <router-view/>
     </keep-alive>

由于被缓存的组件不会被摧毁,若组件内存在定时器,定时器也不会被停止,一直运行消耗性能,这时可以将定时器写在activated激活生命钩子内,将消除定时器写在deactivated失活生命钩子内。

activated激活生命钩子和deactivated失活生命钩子是路由组件独有的生命周期钩子。

    activated(){
        this.timer = setInterval(() => {
            console.log('@');
        }, 500);
    },
    deactivated(){
        clearInterval(this.timer)
    }

关于路由更多详情请见Vue Router官方文档。