Vue 自定義VueRouter-簡版


😜 主要是思路,自己定義組件的時候可以借鑒 😜

🚀 Vue-router的 類圖

  • name
  • options: ==> 記錄構造函數中傳入的對象,在 new VueRouter的時候傳了一個對象( routes :路由規則)
  • data: ==> 有個屬性 current (記錄當前路由地址的),響應式的數據(地址變化加載不同的組件),需要 Vue.observable方法
  • routeMap: ==> 一個對象,記錄路由地址和組件的對應關系,解析路由規則到 routeMap

  • Constructor(Options):VueRouter
  • _install(Vue):void => 靜態方法,實現 Vue 的插件機制
  • init():void ==> init 方法調用下面3個方法,不同的代碼分割到不同的方法中實現
  • initEvent():void => 注冊 popState 方法,監聽瀏覽器歷史的變化
  • initRouteMap():void => 初始化 routeMap 屬性,把構造函數中傳入的路由規則轉換成鍵值對的形式存儲到 RouteMap({key:path, value:component})中,我們在 router-view 這個組件中會使用這個 routeMap
  • initComponents(Vue):void => 用來創建 router-viewrouter-link 這兩個組件的

🚀 Vue 的構建版本

  • 運行時版: 不支持 template模板, 需要打包的時候提前編譯 -Vue-Cli 創建時默認值, 需要手寫 render函數
  • 完整版: 包含運行時和編譯器, 體積比運行時版大10K左右, 程序運行時把模板轉換成render函數
  • pushState 就是改變瀏覽器地址
let _Vue = null
export default class VueRouter {
  // ----------------------------------- ❗ install section -----------------------------------
  static install(Vue) {
    // 1.判斷當前插件是否已經安裝
    if (VueRouter.install.installed) {
      return
    }
    // 插件被安裝了
    VueRouter.install.installed = true
    // 2.把Vue的構造函數記錄到全局變量
    _Vue = Vue

    // 3.把創建Vue實例時候傳入的router對象注入到Vue實例上(構造函數的原型上新增一個成員,這樣所有的實例都可以訪問到 $router)
    // _Vue.prototype.$router = this.$options.router // 誰調用 this 就是誰, VueRouter.install()調用, 所以不是 Vue 實例,而是VueRouter這個類
    // 混入
    _Vue.mixin({
      beforeCreate() {
        // 這個混入會導致所有的組件都會有,會被執行很多次, 我們只需要執行一次
        // 如果是組件的話就不執行了,如果是Vue實例才執行
        // 判斷條件: $options.router是否存在, 只有在 Vue.$options才有這個屬性,而組件中沒有這個屬性
        if (this.$options.router) {
          _Vue.prototype.$router = this.$options.router // 在這里就是 Vue 實例

          // 🚀 插件注冊成功后執行
          this.$options.router.init()
        }
      }
    })
  }

  // ----------------------------------- ❗ constructor section -----------------------------------
  constructor(options) {
    this.options = options
    this.routeMap = {} // 鍵值對對象 路由: 組件
    this.data = _Vue.observable({ // 響應式數據
      current: '/'
    })
  }

  // ----------------------------------- ❗ initRouteMap section -----------------------------------
  /**
   * 作用: 把構造函數傳進來的選項中 routes 轉換成鍵值對的形式存儲到 routeMap這個對象中 鍵值對對象 路由: 組件
   */
  initRouteMap() {
    // 遍歷 路由規則 轉換成鍵值對的形式存儲到 routeMap這個對象中
    this.options.routes.forEach(route => {
      this.routeMap[route.path] = route.component
    })
  }

  // ----------------------------------- ❗ initComponents section -----------------------------------
  /**
   * 創建 router-link:
   * 創建 router-view:
   * 參數: Vue的構造函數,可以不傳遞,我們有全局變量記錄,為了減少外部依賴最好傳遞
   */
  initComponents(Vue) {
    Vue.component('router-link', {
      props: {
        to: String
      },
      // template: '<a :href="to"><slot></slot></a>'
      /**
       * h 這個函數的作用創建 虛擬DOM
       */
      render(h) {
        // 參數1: 選擇器, 參數2: 屬性, 參數3: 子元素
        return h('a', {
          attrs: {
            href: this.to // 不加 # 以 history模式
          },
          on: {
            click: this.clickHanlder // 注冊事件,不加括號
          }
        }, [this.$slots.default])
      },
      methods: {
        clickHanlder(e) {
          // data, title, url
          history.pushState({}, '', this.to)
          this.$router.data.current = this.to
          e.preventDefault()
        }
      }
    })
    // 暫存 Vue對象
    const self = this
    Vue.component('router-view', {
      render(h) {
        // self.data.current // 當前路由地址
        const component = self.routeMap[self.data.current]
        return h(component)
      }
    })
  }

  // ----------------------------------- ❗ init section -----------------------------------
  // 包裝 initComponents 和 initRouteMap
  init() {
    this.initRouteMap()
    this.initComponents(_Vue)
    this.initEvent()
  }

  // ----------------------------------- ❗ initEvent -----------------------------------
  // 箭頭函數不會改變this的指向,initEvent的this就是VueRouter
  initEvent() {
    window.addEventListener('popstate', () => {
      this.data.current = window.location.pathname
    })
  }
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM