手撕Vue-Router-實現router-link

BNTang發表於2023-11-29

前言

在上一篇 [手撕Vue-Router-新增全域性$router屬性] 中,實現了將每一個 Vue 例項上掛載一個 $router 屬性,這個屬性就是我們在上一篇文章中建立的 VueRouter 例項。

開始

本章節,我們將實現一個 router-link 元件,這個元件可以實現點選跳轉到指定的路由。

實現思路

我們需要實現一個 router-link 元件,這個元件可以實現點選跳轉到指定的路由。

實現 router-link 元件,我們需要注意以下幾點:

  • 只要外界使用了Vue-Router, 那麼我們就必須提供兩個自定義的元件給外界使用,一個是 router-link 元件,一個是 router-view 元件。
  • 只要外界透過Vue.use註冊了Vue-Router, 就代表外界使用了Vue-Router
  • 只要外界透過Vue.use註冊了Vue-Router, 就會呼叫外掛的install方法
  • 所以我們只需要在install方法中註冊兩個全域性元件給外界使用即可

程式碼實現

  • 只要外界使用了Vue-Router, 那麼我們就必須提供兩個自定義的元件給外界使用,一個是 router-link 元件,一個是 router-view 元件。首先本章節我們只實現 router-link 元件。
  • 只要外界透過Vue.use註冊了Vue-Router, 就代表外界使用了Vue-Router
  • 只要外界透過Vue.use註冊了Vue-Router, 就會呼叫外掛的install方法
  • 所以我們只需要在install方法中註冊兩個全域性元件給外界使用即可

程式碼如下:

NueRouter.install = (Vue, options) => {
    ...

    Vue.component('router-link', {

    });
}

好了到此為止,就完成了新增 router-link 元件,只是簡簡單單的新增了一個元件,還沒有實現跳轉的功能。

實現跳轉功能

透過觀察官方的 router-link 元件,我們可以發現,這個元件是一個 <a> 標籤,所以我們可以透過 <a> 標籤的 href 屬性來實現跳轉。

這麼一來,在根據 Vue 官方文件中介紹的元件註冊方式,我們可以在 component 中使用 render 函式來實現渲染 a 標籤。

a 標籤渲染完畢了但是跳轉的地址還沒有,還需要在 component 中新增一個 props 屬性,這個屬性就是我們要跳轉的地址。

總結:透過 render 函式渲染 a 標籤,透過 props 屬性傳遞跳轉地址。

程式碼如下:

Vue.component('router-link', {
    props: {
        to: {
            type: String,
        }
    },
    render() {
        return <a href={this.to}></a>
    }
});

寫完發現,a 標籤渲染了,但是沒有內容,我們需要在 a 標籤中新增內容,這個內容就是我們在使用 router-link 元件時傳入的內容。

我們可以透過 this.$slots.default 來獲取到我們在使用 router-link 元件時傳入的內容。

程式碼如下:

return <a href={this.to}>{this.$slots.default}</a>

測試自己寫的 router-link 元件,發現可以改變了,發現還有一個問題,就是路由的 mode 為 hash 時,生成的 a 標籤的 href 屬性是 /#/xxx,如果 mode 為 history 時,生成的 a 標籤的 href 屬性是 /xxx, 這個問題我們還需要解決。

那麼怎麼獲取到路由的 mode 呢?我們可以透過 this.$router.mode 來獲取到路由的 mode。

這裡有一個注意點:

render 方法中的 this 並不是當前例項物件, 而是一個代理物件, 如果我們想拿到當前例項物件,那麼可以透過 this._self 獲取

知道了這些內容之後,我們就可以透過 this._self.$router.mode 來獲取到路由的 mode 了。根據路由的 mode 來判斷生成的 a 標籤的 href 屬性。

程式碼如下:

render() {
    let path = this.to;
    if (this._self.$router.mode === 'hash') {
        path = '#' + path;
    }
    return <a href={path}>{this.$slots.default}</a>
}

測試一下,發現可以了。好了,到此為止,我們就完成了 router-link 元件的實現。

最後

大家好我是 BNTang, 一個熱愛分享的技術的開發者,如果大家覺得我的文章對你有幫助的話,可以關注我的公眾號 JavaBoyL,我會在公眾號中分享一些IT技術和一些個人的見解,謝謝大家的支援。

相關文章