vue總結

原文地址html

vue(前端框架)解決了什麼問題?

如今的前端頁面元素愈來愈多,結構也變得愈來愈複雜,當數據和視圖混合在一塊兒的時候對它們的處理會十分複雜,同時也很容易出現錯誤,而現代框架使用聲明式語法,描述組件對象的嵌套關係,並自動生成與dom對象的對應關係
參考1前端

vue生命週期

vue生命週期 描述
beforeCreate 組件實力被建立,el和數據對象都爲undefined,還未初始化
create 數據已經被初始化,而且初始化了Vue內部事件,可是DOM還未生成
befroeMount 完成了模板的編譯。把data對象裏面的數據和vue的語法寫的模板編譯成了虛擬DOM
mouted 執行了render函數,將渲染出來的內容掛載到了DOM節點上
beforeUpdate 組件更新以前:數據發生變化時,會調用beforeUpdate,而後經歷DOM diff
updated 組件更新後
actived keep-alive組件被激活
deactivated keep-alive移除
beforeDestroy 組件銷燬前
destroyed 組件銷燬後

簡述Vue的響應式原理

能夠問數據變更如何和視圖聯繫在一塊兒?
Vue是採用數據劫持結合發佈者-訂閱者模式的方式, Vue相應系統有三大核心: observe, dep, watcher; 精簡版Vue代碼參考
  • Observe:當一個Vue實例建立時,initData階段,vue會遍歷data選項的屬性(observe),用 Object.defineProperty 將它們轉爲 getter/setter而且在內部追蹤相關依賴(dep),在屬性被訪問和修改時通知變化。
  • Compite:調用compile方法解析模版,當視圖中有用到vue.data中數據的時候,會調用實例化watcher方法進行依賴收集
  • Watcher:是ObserverCompile之間通訊的橋樑,當視圖中遇到綁定的數據時,在watcher方法中會獲取這個數據,此時會觸發observe中的getter方法,
  • Dep:發佈訂閱模式,observe中數據的getter被觸發時會收集依賴的watcher(dep.depend方法)
  • 當有數據被改動時會觸發observe中數據的setter,此時會調用dep.notify方法給全部訂閱的watcher發通知(經過回掉方式)進行視圖更新,此時會進行diff流程:

vue中data爲何必需要是一個函數

vue中的data爲對象,是引用類型,當重用組件時,一個組件對data作了更改,那麼另外一個組件也會跟着改,而使用返回一個函數返回數據,則每次返回都是一個新對象,引用地址不用,因此就不會出現問題

Virtual DOM 是什麼

虛擬DOM是一個JavaScript對象,包含了當前DOM的基本結構和信息,它的存在是爲了減小對操做無用DOM所帶來的性能消耗,在大量的、頻繁的數據更新下可以對視圖進行合理的高效的更新(細粒度的精準修改),同時也抽象了原來的渲染過程,實現了跨平臺的能力vue

簡述vue中的DOM DIFF算法

精簡源碼;當數據發生改變時,set方法會讓調用Dep.notify通知全部訂閱者Watcher,訂閱者就會調用patch給真實的DOM打補丁(兩個重要函數patchVnodeupdateChildren):node

  • 先判斷根結點及變化後的節點是不是sameVnode,若是不是的化,就會建立新的根結點並進行替換
  • 若是是sameVnode,則進入patchVnode函數,其基本判斷react

    1. 若是兩個節點是相等oldVnode === vnode則直接return
    2. 若是新節點是文本節點,則判斷新舊文本節點是否一致,不一致(oldVnode.text !== vnode.text)則替換
    3. 若是新節點不是文本節點,則開始比較新舊節點的子節點oldChch
    4. 若是子節點都存在,則進行updateChildren計算(稍後講)
    5. 若是只有新子節點存在,則若是舊節點有文本節點,則移除文本節點,而後將新子節點拆入
    6. 若是只有舊子節點存在,則移除全部子節點
    7. 若是均無子節點且舊節點是文本節點,則移除文本節點(此時新節點必定不是文本節點)
  • updateChildren函數作細緻對比git

    1. start && oldStart對比
    2. end && oldEnd對比
    3. start && oldEnd對比
    4. end && oldStart 對比
    5. 生成map映射,(key:舊子節點上的key,value:舊子節點在本身點中的位置),根據key記錄下老節點在新節點的位置(idxInOld
      1) 若是找到了idxInOld,若是是相同節點則移動舊節點到新的對應的地方,不然雖然key相同但元素不一樣,看成新元素節點去建立
      2) 若是沒有找到idxInOld,則建立節點
    6. 若是老節點先遍歷完,則新節點比老節點多,將新節點多餘的插入進去
    7. 若是新節點先遍歷完,則就節點比新節點多,將舊節點多餘的刪除

vue中key的做用

主要是爲了複用節點,高效的更新虛擬DOM,另外,在使用標籤元素過渡效果時也會用到keygithub

computed的原理

  • vue對象初始化的同時對計算屬性進行初始化initComputed,
  • computed會對初始化的Watcher傳入lazy: true就會觸發Watcher中的watcher.dirty=true(dirty決定了當前屬性是否更新),
  • 當視圖中有對computed引用的時候會第一次執行計算屬性,並將dirty設置爲false,並將結果保存在this.value中進行緩存,
  • 若是依賴沒有更改,則下次獲取computed會這直接返回this.value,只有當computed所依賴的屬性發生變化時會將dirty設置爲true,並從新計算
class Watcher{
  ……
  evaluate () {
    this.value = this.get()
    this.dirty = false
  }
  ……
}

class initComputed{
  …… 
  //計算屬性的getter 獲取計算屬性的值時會調用
    createComputedGetter (key) {
      return function computedGetter () {
          //獲取到相應的watcher
        const watcher = this._computedWatchers && this._computedWatchers[key]
        if (watcher) {
             //watcher.dirty 參數決定了計算屬性值是否須要從新計算,默認值爲true,即第一次時會調用一次
              if (watcher.dirty) {
                  /*每次執行以後watcher.dirty會設置爲false,只要依賴的data值改變時纔會觸發
                  watcher.dirty爲true,從而獲取值時重新計算*/
                watcher.evaluate()
              }
              //獲取依賴
              if (Dep.target) {
                watcher.depend()
              }
              //返回計算屬性的值
              return watcher.value
        }
      }
    }
  ……
}

計算屬性computed和watch的區別

計算屬性顧名思義就是經過其餘變量計算得來的,它的值是基於其所依賴的屬性來進行緩存的,只有在其所依賴的屬性發生變化時纔會重新求值
watch是監聽一個變量,當變量發生變化時,會調用對應的方法算法

對$nextTick的理解

vue實現響應式並非數據一更新就馬上觸發dom變化,而是按照必定的策略對dom進行更新,源碼位置,原理:vue-router

  • 首先會將全部的nextTick放到一個函數中,而後放在callbacks數組中,$nextTick沒有傳cb回掉,則返回一個promise
  • 接下來就是callbacks的執行時機數組

    • 首先若是瀏覽器是否兼容promise,則用promise.resolve().then來執行callbacks
    • 若是瀏覽器兼容MutationObserver,則用實例化的MutationObserver監聽文本變化來執行回掉,
    • 若是兼容setImmediate,則用setImmediate(cb)來執行回掉
    • 最後降級爲用setTimeout(fn,0)來執行
  • vue2.5.X版本中對於像v-on這樣的DOM交互事件,默認走macroTimerFunc,也就是,跳過第一步promise的判斷,

子組件爲什麼不能夠修改父組件傳遞的 Prop,是如何監控並給出錯誤提示的

  • 單向數據流,易於監測數據的流動,出現了錯誤能夠更加迅速的定位到錯誤發生的位置
  • initProps時,會對props進行defineReactive操做,傳入的第四個參數是自定義的set報錯判斷函數,該函數會在觸發props的set方法時執行
// src/core/instance/state.js 源碼路徑
function initProps (vm: Component, propsOptions: Object) {
  ...
  for (const key in propsOptions) {
    if (process.env.NODE_ENV !== 'production') {
      ...
      defineReactive(props, key, value, () => {
        // 若是不是跟元素而且不是更新子元素
        if (!isRoot && !isUpdatingChildComponent) {
          warn(
            `Avoid mutating a prop directly since the value will be ` +
            `overwritten whenever the parent component re-renders. ` +
            `Instead, use a data or computed property based on the prop's ` +
            `value. Prop being mutated: "${key}"`,
            vm
          )
        }
      })}
    ...
  }
}
// src/core/observer/index.js
export function defineReactive (obj,key,val,customSetter,shallow) {
  const property = Object.getOwnPropertyDescriptor(obj, key)
  
  const getter = property && property.get
  const setter = property && property.set
  
  Object.defineProperty(obj, key, {
    ...
    set: function reactiveSetter (newVal) {
      const value = getter ? getter.call(obj) : val
      if (newVal === value || (newVal !== newVal && value !== value)) {
        return
      }
      if (process.env.NODE_ENV !== 'production' && customSetter) {
        customSetter()
      }
      if (getter && !setter) return
      if (setter) {
        setter.call(obj, newVal)
      } else {
        val = newVal
      }
      childOb = !shallow && observe(newVal)
      dep.notify()
    }
  })
}

父子組件的生命週期執行順序

加載過程:父組件beforeCreate => 父組件created => 父組件beforeMount => 子組件beforeCreate => 子組件created => 子組件 beforeMount => 子組件mounted => 父組件mounted
更新過程:父組件beforeUpdate => 子組件beforeUpdate => 子組件updated => 父組件updated
銷燬過程:父組件beforeDestroy => 子組件 beforeDestroy => 子組件 destoryed => 父組件 destoryed

vue-router的導航解析流程

官網

  1. 導航被觸發。
  2. 在失活的組件裏調用離開守衛。
  3. 調用全局的 beforeEach 守衛。
  4. 在重用的組件裏調用 beforeRouteUpdate 守衛 (2.2+)。
  5. 在路由配置裏調用 beforeEnter
  6. 解析異步路由組件。
  7. 在被激活的組件裏調用 beforeRouteEnter
  8. 調用全局的 beforeResolve 守衛 (2.5+)。
  9. 導航被確認。
  10. 調用全局的 afterEach 鉤子。
  11. 觸發 DOM 更新。
  12. 用建立好的實例調用 beforeRouteEnter 守衛中傳給 next 的回調函數。

router.beforeResolve 註冊一個全局守衛。這和 router.beforeEach 相似,區別是在導航被確認以前,同時在全部組件內守衛和異步路由組件被解析以後,解析守衛就被調用

僅表明我的看法,能力有限,若有錯誤會誤人子弟的地方歡迎留言指出;謝謝

相關文章
相關標籤/搜索