Vue3 封装一个 router-links ,支持内外链接都能跳转
<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>
效果如下:
更高的灵活性
在新窗口中打开
我们可以多添加一些常用的功能。例如,我们希望外部链接都在新窗口中打开,这样很简单就能做到了,只要把 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 思路讲完了,当然,大家需要新的需求可以自行扩展。
原文链接:点击这里
码云笔记 » Vue3 封装一个 router-links ,支持内外链接都能跳转