2x3 VueRouter - 进阶 - 组合式 API

2,799 阅读2分钟

VueRouter 基础教程系列 🎉

CompositionAPI 的方式来使用 VueRouter 首要注意的就是无法在 setup 中通过 this 来访问组件实例。但这并不影响模板与组件实例的绑定关系(含义就是模板中依然可以通过组件实例来访问 $route$router 对象)。

route 与 router

由于 setup 中无法通过 this 来访问组件实例,因此无法直接访问 this.$routerthis.$route。作为替代,我们使用 useRouter 函数来分别获取路由记录对象 (route) 和 路由器对象 (router)。

const {route, router} = useRouter();

⚠️ 注意,route 对象整个都是响应式的,所以我们要避免监听整个 route 对象,而是监听它的具体属性。

watch(()=>route.params, async newParams=> {
   userData.value = await fetchUser(newParams.id)
});

路由导航守卫

VueRouter 提供了 onBeforeRouteUpdateonBeforeRouteLeave 两个组合式函数的导航守卫。

import { defineComponent, onBeforeRouteUpdate, onBeforeRouteLeave } from 'vue';

defineComponent({
    setup() {
        //路径参数发生改变后,重新请求数据。
        onBeforeRouteUpdate(async (to, from) => {
            if (to.params.id !== from.params.id) {
                userData.value = await fetchUser(to.params.id)
            }
        });

        onBeforeRouteLeave((to, from) => {
            const answer = window.confirm(
                'Do you really want to leave? you have unsaved changes!'
            )
            // 取消导航并停留在同一页面上
            if (!answer) return false
        })
    }
});

⚠️ 谨记,VueRouter 只提供了这两个组合函数风格的导航守卫,并没有提供 beforeRouteEnter

当路由仅是路径参数、queryhash 发生改变,而不是 path 发生改变时,那么路由组件就会被复用,此时便会触发 onBeforeRouteUpdate

useLink

useLink 组合函数公开了 router-link 组件在导航时其内部所产生的行为与信息。这些行为和信息与通过 router-link 作用域插槽 (v-slot) 所接收的属性完全相同。

<router-link v-slot="{route, href, isActive, isExactActive, navigat}">
    {{href}}
</router-link>

useLink 函数所接收的参数与 router-link 所接收的 props 完全一致。

就是说可以通过 useLink 函数获取 router-link 跳转时产生的行为与信息,但并不会真实发生跳转行为。

const { route, href, isActive, isExactActive, navigate } = useLink({to:'/'}); 

我们可以将 useLink 的功能看作是对 router-link 的一次预解析。通过预解析,我们可以对 router-link 再封装,以更丰富的方式来应对我们需求中不同形式的链接的跳转,例如内部链接、外部链接(第三方链接)、是否新窗口打开等。

import { RouterLink, useLink } from 'vue-router'

export default {
  name: 'AppLink',

  props: {
    // 如果使用 TypeScript,请添加 @ts-ignore
    ...RouterLink.props,
    inactiveClass: String,
  },

  setup(props) {
    const { route, href, isActive, isExactActive, navigate } = useLink(props)

    const isExternalLink = computed(
      () => typeof props.to === 'string' && props.to.startsWith('http')
    )

    return { isExternalLink, href, navigate, isActive }
  },
}

⚠️ 在跳转第三方链接时,为了我们页面的性能与安全,强烈建议为 a 标签设置 rel="noopener"