Vue-5 路由参数的传递和获取(query 和 params),导航守卫和路由元信息,History模式

Vue-5 路由传参的几种方式(query和params),获取路由参数,导航守卫和路由元信息,History模式

除了 props$emit 之外,路由时也可以携带数据,即通过路由传参。

一、路由参数的传递和接收

1. 动态路由的匹配

示例需求:有个商品详情的组件,点击任何商品都会渲染这个组件,点击商品时向详情组件传递商品的 id,详情组件在被渲染时接收这个 id,请求对应的数据,渲染在详情组件上。

可以在配置路由时直接为参数预留路径:

// router>index.js 的routes
routes: [
    {
        // 在路径中预留参数的位置
        path: '/good-detail/:id',
        component: Detail
    }
]

调用:


<router-link to="/good-detail/1">商品1router-link>
<router-link to="/good-detail/2">商品2router-link>
<router-link to="/good-detail/3">商品3router-link>


<router-view />

接收参数:


<div class="detail">
    
    {{ this.$route.params.id }}
div>
// 如果想要在组件刚开始加载时获取 id,并且根据 id 做一些数据操作,那就在对应的钩子函数中,获取路由参数
created() { // detail 组件生命周期的 created 钩子函数
    const id = this.$route.params.id;
    // code
}

createdmounted 函数,只能在第一个商品被渲染时响应,detail 组件在第一次被渲染之后,虽然路由变了,但是 createdmounted 不会重新执行。这种情况下,可以用 updated 来动态获取路由参数。也可以用 watch 来监听路由的变化。

watch: {
    // to 和 from 分别表示路由切换前后的路由元信息
    '$route'(to, from) {
      // 对路由变化作出响应...
    }
}

2. router-link 的 to属性传参

如果使用 标签的 to 属性动态传参,那么路由配置时不需要在 path 路径中预留参数的位置,直接传参并接收就可以了。

// router>index.js 的routes
routes: [
    {
        // 路径中不需要预留参数的位置
        path: '/good-detail',
        component: Detail
    }
]

传参:


<router-link 
    :to="{
        path: '/good-detail',
        query: {
            id: 1
        }
    }"
>商品3router-link>

接收参数:

// detail 组件的 created 钩子函数
created() {
    const id = this.$route.query.id;
    // code
}

这样传参,有个好处,就是有多个参数时,无论是配置还是传参,代码都非常简洁,如果有多个参数,直接列在 query 对象中就可以了。

但是也有个缺点,就是传递的参数会暴露在 url 中,如果参数中的信息是需要保护的信息,那么直接暴露就没有任何安全性了。

这就要用到 paramsparamsquery 的区别就是 params 中的参数不会暴露在 url 中,query 会。

但是 params 需要和路由的 name 结合使用。

// router>index.js 的routes
routes: [
    {
        path: '/good-detail',
        name: 'good-detail',
        component: Detail
    }
]
<router-link 
    :to="{
        name: 'good-detail',
        params: {
            id: 1
        }
    }"
>商品3router-link>

获取 params 中的参数:

// detail 组件的 created 钩子函数
created() {
    const id = this.$route.params.id;
    // code
}

注:
path 只能和 query 结合使用,name 可以和 query 或者 params 结合使用,但是 namequery 结合使用时,参数依旧会暴露。

3. push 时传参

// path 和 query 结合使用
this.$router.push({
    path: '/good-detail',
    query: {
        id: 1
    }
});

// name 和 query 结合使用
this.$router.push({
    name: 'good-detail',
    query: {
        id: 1
    }
});

// name 和 params 结合使用
this.$router.push({
    path: '/good-detail',
    params: {
        id: 1
    }
});

接受参数方式不变。

二、导航守卫和路由元信息

1. 导航守卫

通俗点说,导航守卫指在路由切换时,对组件中的数据或者用户信息做一些保护和判断。

比如用户从 A 组件切换到 B 组件,但是 B 组件中的内容是要根据用户的权限渲染的,不同权限的用户渲染不同的内容。就需要在切换之前拿到用户的权限信息,做判断之后再切换组件。

还有一种可能性,某个后台管理系统只能在用户登录之后才展示相对应的页面,但是用户可能已经知道了首页的路径,用户可能没经过登录直接在浏览器输入首页路径,要强行进入首页,那么在此之前,我们要做导航守卫。

其实我们可以把导航守卫理解成路由过程中的钩子函数。

全局守卫

// router>index.js
import Vue from 'vue'
import Router from 'vue-router'

Vue.use(Router)

const router =  new Router({
  routes: [
      // ...
  ]
});

// 全局前置守卫
router.beforeEach((to, from, next) => {
    // code
});

// 全局后置钩子
router.afterEach((to, from) => {
  // ...
});

export default router

全局的守卫会在每个路由发生变化时响应,但是有时候我们只需要在某个路由发生变化时做一些操作,并不需要所有路由全部响应切换。全局守卫的循环还是稍微有点耗性能。

某个路由自己的守卫

import Vue from 'vue'
import Router from 'vue-router'

import GoodDetail from '@/components/GoodDetail'

Vue.use(Router)

export default new Router({
    routes: [
        {
            path: '/good-detail',
            component: GoodDetail,
            beforeEnter: (to, from, next) => {
                // 只有当前路由切换时要响应的代码
                // 和其他路由没有任何关系
            }
        }
    ]
})

如果需要在某个组件中,捕获到路由变化之后或者之前,对数据做一些保留或清除动作。

比如从商品列表切换到商品详情,我们可以在详情组件路由切换成功的钩子函数中,获取路由参数,就可以使用组件中的路由守卫(当然也可以用组件生命周期钩子函数,也可以使用watch,这里组件中的路由守卫只是提供另一种可能性)。

组件内的守卫

// 某个组件的 export 
export default {
    name: 'Detail',
    // vue-router 文档提供的示例
    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,因为守卫在导航确认前被调用,因此即将登场的新组件还没被创建。

完整的导航流程解析

官网给了导航切换的整个细致流程及每个阶段的钩子函数。

  • 导航被触发。
  • 在失活的组件里调用离开守卫。
  • 调用全局的 beforeEach 守卫。
  • 在重用的组件里调用 beforeRouteUpdate 守卫 (2.2+)。
  • 在路由配置里调用 beforeEnter。
  • 解析异步路由组件。
  • 在被激活的组件里调用 beforeRouteEnter。
  • 调用全局的 beforeResolve 守卫 (2.5+)。
  • 导航被确认。
  • 调用全局的 afterEach 钩子。
  • 触发 DOM 更新。
  • 用创建好的实例调用 beforeRouteEnter 守卫中传给 next 的回调函数。

to, from, next

在上面的很多例子中,我们都能看到 钩子函数接收的参数,to,from,next。它们都代表特殊的意义和作用。

  • 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() 注册过的回调。

2. 路由元信息

在配置路由时,路由对应的某些固定数据,我们可以直接绑定在路由配置对象的 meta 对象中,然后在需要时获取。

// router>index.js 的 routes
routes: [
    {
        path: '/good-detail',
        component: GoodDetail,
        // 定义路由的时候可以配置 meta 字段:
        meta: {
            title: '商品详情',
            ifSee: true
        }
    }
]

获取路由元信息:

// Detail 组件的 created
created() {
    console.log(this.$route.meta);
}

History 模式

我们在运行项目时,能看到 url 中带有一个 # ,这个是 vue-router 默认的 hash 模式。因为正常情况下,切换浏览器的 url 浏览器中的内容是要刷新的,但是我们希望的是通过在 url 中切换路由来实现页面组件的切换,所以 vue-routerurl 中添加了 # 号,这样在切换路由导致 url 改变时不会刷新页面。其实 标签最终渲染的真实 DOMto 属性是 标签的 href# 是锚点:

<a data-v-957c9522="" href="#/good-detail" class="router-link-exact-active router-link-active">详情a>

如果不想要很丑的 hash,我们可以用路由的 history 模式,这种模式充分利用 history.pushState API 来完成 URL 跳转而无须重新加载页面。

const router = new VueRouter({
  mode: 'history',
  routes: [...]
})

当使用 history 模式时,URL 就像正常的 url,例如 http://yoursite.com/user/id。

只是设置成 history 之后,一些与后台的数据交互需要依赖后台配置。

你可能感兴趣的:(前端开发,框架)