扩展 RouterLink

RouterLink 组件提供了足够的 props 来满足大多数基本应用程序的需求,但它并未尝试涵盖所有可能的用例,在某些高级情况下,你可能会发现自己使用了 v-slot。在大多数中型到大型应用程序中,值得创建一个(如果不是多个)自定义 RouterLink 组件,以在整个应用程序中重用它们。例如导航菜单中的链接,处理外部链接,添加 inactive-class 等。

让我们扩展 RouterLink 来处理外部链接,并在 AppLink.vue 文件中添加一个自定义的 inactive-class

  1. <template>
  2. <a v-if="isExternalLink" v-bind="$attrs" :href="to" target="_blank">
  3. <slot />
  4. </a>
  5. <router-link
  6. v-else
  7. v-bind="$props"
  8. custom
  9. v-slot="{ isActive, href, navigate }"
  10. >
  11. <a
  12. v-bind="$attrs"
  13. :href="href"
  14. @click="navigate"
  15. :class="isActive ? activeClass : inactiveClass"
  16. >
  17. <slot />
  18. </a>
  19. </router-link>
  20. </template>
  21. <script>
  22. import { RouterLink } from 'vue-router'
  23. export default {
  24. name: 'AppLink',
  25. props: {
  26. // 如果使用 TypeScript,请添加 @ts-ignore
  27. ...RouterLink.props,
  28. inactiveClass: String,
  29. },
  30. computed: {
  31. isExternalLink() {
  32. return typeof this.to === 'string' && this.to.startsWith('http')
  33. },
  34. },
  35. }
  36. </script>

如果你喜欢使用渲染函数或创建 computed 属性,你可以使用 Composition API 中的 useLink

  1. import { RouterLink, useLink } from 'vue-router'
  2. export default {
  3. name: 'AppLink',
  4. props: {
  5. // 如果使用 TypeScript,请添加 @ts-ignore
  6. ...RouterLink.props,
  7. inactiveClass: String,
  8. },
  9. setup(props) {
  10. // toRef 允许我们提取一个 prop 并保持它的响应
  11. // https://v3.vuejs.org/api/refs-api.html#toref
  12. const { navigate, href, route, isActive, isExactActive } = useLink(
  13. toRef(props, 'to')
  14. )
  15. // profit!
  16. return { isExternalLink }
  17. },
  18. }

在实践中,你可能希望将你的 AppLink 组件用于应用程序的不同部分。例如,使用 Tailwind CSS,你可以用所有的类创建一个 NavLink.vue 组件:

  1. <template>
  2. <AppLink
  3. v-bind="$attrs"
  4. class="inline-flex items-center px-1 pt-1 border-b-2 border-transparent text-sm font-medium leading-5 text-gray-500 focus:outline-none transition duration-150 ease-in-out hover:text-gray-700 hover:border-gray-300 focus:outline-none focus:text-gray-700 focus:border-gray-300 transition duration-150 ease-in-out"
  5. active-class="border-indigo-500 text-gray-900 focus:border-indigo-700"
  6. inactive-class="text-gray-500 hover:text-gray-700 hover:border-gray-300 focus:text-gray-700 focus:border-gray-300"
  7. >
  8. <slot />
  9. </AppLink>
  10. </template>