在 Vue3中,封裝一個 router-links,支持內外鏈接都能跳轉!
<router-link>標簽是用于在Vue應用程序的不同頁面之間跳轉,但它不是跳轉到外部鏈接,相反,我們一般使用<a> 標簽。
也許只有我這么認為,但很多時候,我無法跟上這種差異。其他時候,鏈接可能是動態(tài)的,即來自數(shù)據庫或用戶提供的某個數(shù)據源。在這種情況下,你根本不知道鏈接是外部的還是內部的,在每個可能使用鏈接的地方手動做一個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 中,創(chuàng)建 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,因為它包含多個根元素。
現(xiàn)在,我們需要一個計算屬性來告訴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>
外部鏈接的獨特樣式
我見過一些網站在他們的網站上設置的外部鏈接樣式與在他們自己的網站上指向站內的鏈接有點不同。這可以幫助用戶更好地理解他們要跳轉的是外部鏈接。
這個樣式可以是任何東西,如,在第三方鏈接加個警告的圖標,告訴用戶跳轉的風險。在我們的組件中實現(xiàn)這一點非常簡單,只需在模板中的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 思路講完了,當然,大家需要新的需求可以自行擴展。
~完,我是小智,下期見!
作者:Written by Daniel Kelly
譯者:前端小智 來源:vueschoolhttps://vueschol.io/articles/vuejs-tutorials/extendig-vue-router-links-in-vue-3/