Vue-router源碼

前端路由和後端路由

  • 後端路由-mvc:輸入url》請求發送到服務器》服務器解析請求的路徑》獲取對應頁面》返回出去
  • 前端路由-spa:輸入url》js解析地址》找到對應地址的頁面》執行頁面生成的js》看到頁面

vue-router工做流程

  • url改變》觸發監聽事件》改變vue-router裏面的current變量》監視current變量的監視者》獲取新的組件》render新組件

路由模式

hash

  • #號後面的內容
  • 能夠經過location.hash拿到
  • 經過onhashchange監聽改變
  • 只會把路由給到服務器,並不會發生跳轉

history

  • 經過location.pathname來獲取路徑
  • 經過onpopstate監聽history的改變

Vue.use

  • 若是傳進去的是一個函數的話,就執行這個函數
  • 若是函數/對象的install是一個方法的話,就會優先執行這個方法,而不去執行自己這個函數
function a() {
  console.log('函數自己的方法');
}
a.install = function () {
  console.log('install的方法');
}
Vue.use(a)//install的方法複製代碼
  • Vue.use()會向install這個方法傳入一個vue的類(都是相等的都是Vue的類)

  • 這個類下面有個mixin的方法(能夠向vue實例混入各類data,methods或者各類,至關於全局引入)
a.install = function (Vue) {
  Vue.mixin({
    data(){
      return{
        //均可以在任何組件調用這個name
        name:"zxx"
      }
    }
  })
}複製代碼
  • 最重要的仍是能夠混入生命週期函數,能夠拿到各個組件的this
    //能夠拿到各個組件實例的this
    created(){
      console.log(this);
    }複製代碼
  • vue有一系列util,下面有一些方法

  • 並且這些方法都是暴露出來的能夠直接使用
  • 其中defineReactive就是數據響應原理的方法
//vue外面的對象
var test={
  testa:1
}
//進行數據綁定
Vue.util.defineReactive(test,'testa')
//2秒以後改變
setTimeout(function(){
  test.testa=333
},2000)
a.install = function (Vue) {
  Vue.mixin({
    //混入下面的組件
    beforeCreate(){
      this.test=test
    },
    created(){
    }
  })
}複製代碼
  • 放在beforeCreate是由於這時候this尚未建立,放到created的話,this已經建立了
  • 單其實測試發現,放在2個裏面都同樣的,均可以正常運行

代碼前端

class History {
  constructor() {
    this.current = null
  }
}

class VueRouter {
  constructor(options) {
    this.mode = options.mode || 'hash';
    this.routes = options.routes || [];
    this.history = new History;
    this.routesMap = this.createMap(this.routes)
    this.init()
  }
  init() {
    if (this.mode === 'hash') {
      //若是爲false的話,那麼執行後面的語句,改爲/
      //若是爲true的話,執行'',不改變任何東西
      location.hash ? '' : location.hash = '/';
      window.addEventListener('load', () => {
        this.history.current = location.hash.slice(1)
      })
      window.addEventListener('hashchange', () => {
        this.history.current = location.hash.slice(1)
      })
    } else {
      location.pathname ? '' : location.pathname = '/';
      window.addEventListener('load', () => {
        this.history.current = location.pathname
      })
      window.addEventListener('popstate', () => {
        this.history.current = location.pathname
      })
    }
  }
  createMap(routes) {
    return routes.reduce((prev, item) => {
      prev[item.path] = item.component
      return prev
    }, {})
  }
}
VueRouter.install=function(Vue){
  Vue.mixin({
    //全局混入了router實例,而且作了響應式綁定
    beforeCreate() {
      if (this.$options && this.$options.router) {
        this._root = this;
        this._router = this.$options.router
        Vue.util.defineReactive(this, 'current', this._router.history)
      } else {
        this._root = this.$parent._root
      }
    }
  })
  Vue.component('router-view', {
    render(h) {
      let current = this._self._root._router.history.current;
      console.log(current);
      let routesMap = this._self._root._router.routesMap
      console.log(routesMap);
      return h(routesMap[current])
    }
  }
  )
}

export default VueRouter複製代碼
相關文章
相關標籤/搜索