在 Vue3中,封装一个 router-links ,支持内外链接都能跳转!

  • Post author:
  • Post category:vue


作者:Written by Daniel Kelly

译者:前端小智

来源:vueschool

有梦想,有干货,微信搜索

【大迁世界】

关注这个在凌晨还在刷碗的刷碗智。

本文 GitHub

https://github.com/qq449245884/xiaozhi

已收录,有一线大厂面试完整考点、资料以及我的系列文章。


<router-link>

标签是用于在Vue应用程序的不同页面之间跳转,但它不是跳转到外部链接,相反,我们一般使用

<a>

标签。

也许只有我这么认为,但很多时候,我无法跟上这种差异。其他时候,链接可能是动态的,即来自数据库或用户提供的某个数据源。在这种情况下,你根本不知道链接是外部的还是内部的,在每个可能使用链接的地方手动做一个

v-if

是多么痛苦。

如果只用一个组件来处理所有内部和外部的链接,那不是很好吗?

幸运的是,扩展

<router-link>

组件非常简单,只需将它包装到我们自己的定制组件中。Ok,我们需要构建一个

AppLink

组件来处理链接,无论是外部的还是内部的。




AppLink

组件


AppLink

组件的 props 要包含

router-link

的所有

props

。为什么? 因为这样我们组件的“接口”就可以模仿 Router Link 的接口,无需再记住另一个API。 我们可以通过从Vue Router导入 RouterLink 并将其

props

解构到我们的组件中,如下所示:

// AppLink.vue
<script>
import {RouterLink} from 'vue-router'
export default{
  props:{ ...RouterLink.props }
}
</script>



template

中,创建

router-link

并将 props 传递给它,我们还需要传入

slot

,这个可以在

router-link

插入内容。

// AppLink.vue
<template>
  <router-link v-bind="$props"><slot /></router-link>
</template>

到目前为止,我们已经处理了所有内部链接,那外部链接呢? 如前所述,外部链接使用

a

标签,因此我们将其添加到

template

中。 像 router link 一样,并将传入的

to

值赋值给

href

// AppLink.vue
<template>
  <a :href="to"><slot/></a>
  <router-link v-bind="$props"><slot/></router-link>
</template>

这样内部和外部链接都有了对应的处理,需要注意的是,以上内容仅适用于 Vue3,因为它包含多个根元素。

现在,我们需要一个计算属性来告诉

AppLink

使用哪种链接,我们先取名为

isExternal

首先,我们检查

prop

的值是否为字符串。 这是必需的,因为

to

属性可能是一个对象,例如有时传递到

router-link

(即:

:to="{name:'RouteNameHere'}"

)。 然后,我们将查字符串是否以

http

字符串开头。 如果这两个条件都成立,那么就判断是一个外部链接。

// AppLink.vue
<script>
export default{
   //...
  computed:{
    isExternal(){
      return typeof this.to === 'string' && this.to.startsWith('http')
    }
  }
}
</script>

有了

isExternal

计算属性之后,我们就可以使用

v-if

来进行操作,如下所示:

// AppLink.vue
<template>
  <a v-if="isExternal" :href="to"><slot/></a>
  <router-link v-else v-bind="$props"><slot/></router-link>
</template>

大功告成,我们可以这样来使用 AppLink 组件。

// Anywhere in your app
<AppLink :to="[external-or-internal-link]">Click Me</AppLink>

1070327365-609ea6b57addd.gif



更高的灵活性



在新窗口中打开

我们可以多添加一些常用的功能。例如,我们希望外部链接都在新窗口中打开,这样很简单就能做到了,只要把

target="_blank"

添加到我们的

a

标签中即可。

// AppLink.vue
<template>
  <a ... target="_blank"><slot/></a>
  ...
</template>

当然,有些外部链接不需要在新窗口中打开,我们可以通过指定

target

来告诉组件内部打开链接的方式,如下所示:

<AppLink :to="https://vueschool.io" target="_self">Vue School</AppLink>



链接安全

当我们使用

target="_blank"

属性链接到另一个站点上的页面时,最终可能使我们的站点面临性能和安全性问题:

  • 链接到的页面最终可以在与页面相同的进程上运行。 根据所链接页面的最新情况,这可能会使您自己的页面变慢。

  • 另一个页面也可以通过

    window.opener

    属性访问原始页面窗口,从而引起安全隐患。

解决此问题的方法是为所有外部链接标签添加

rel="noopener"

属性,因为我们已经封装成组件了,所以只需要在组件内部的

a

标签添加即可。

// AppLink.vue
<template>
  <a ... rel="noopener"><slot/></a>
  ...
</template>



外部链接的独特样式

我见过一些网站在他们的网站上设置的外部链接样式与在他们自己的网站上指向站内的链接有点不同。这可以帮助用户更好地理解他们要跳转的是外部链接。

这个样式可以是任何东西,如,在第三方链接加个警告的图标,告诉用户跳转的风险。在我们的组件中实现这一点非常简单,只需在模板中的

a

标签中添加一个

external-link

类,然后使用css对其进行不同的样式化:

// AppLink.vue
// (must have font awesome font included in project)
<template>
  <a ... class="external-link">
    <slot/> <i class="fas fa-external-link-alt"></i>
  </a>
  ...
</template>

<style scoped>
.external-link i {
  font-size: 0.8em;
  opacity: 0.7;
}
</style>

这里就把 AppLink 思路讲完了,当然,大家需要新的需求可以自行扩展。

~完,我是小智,看海贼王去了,下期见!


编辑中可能存在的bug没法实时知道,事后为了解决这些bug,花了大量的时间进行log 调试,这边顺便给大家推荐一个好用的BUG监控工具

Fundebug


https://vueschol.io/articles/vuejs-tutorials/extendig-vue-router-links-in-vue-3/



交流

文章每周持续更新,可以微信搜索**【大迁世界 】

第一时间阅读,回复

【福利】**有多份前端视频等着你,本文 GitHub

https://github.com/qq449245884/xiaozhi

已经收录,欢迎Star。



版权声明:本文为qq449245884原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。