web前端知識點(VUE篇)

vue是一套用於構建用戶界面的漸進式框架。與其它大型框架不同的是,Vue 被設計爲可以自底向上逐層應用。Vue 的核心庫只關注視圖層,不僅易於上手,還便於與第三方庫或既有項目整合。

vue是一個MVVM框架,MVVM是一個MVC框架的改進版,由model-view-viewModel三塊組成,由viewModel來是實現數據(model)和視圖(view)之間的通信。

生命週期

生命週期中有多個事件鉤子,讓我們在控制整個Vue實例的過程時更容易形成好的邏輯。

beforeCreate、created、beforeMounted、mounted、beforeUpdate、updated、beforeDestroy、destroyed。

底層實現原理

vue是一個MVVM的單向數據流,數據雙向綁定的框架,2.0的雙向數據綁定是由Object.defineProperty來實現,3.0是由Object.proxy來實現。

具體實現流程:

  • Observer:核心是通過Obeject.defineProperty()來監聽數據的變動,這個函數內部可以定義setter和getter,每當數據發生變化,就會觸發setter,進行數據劫持,然後通知訂閱者,訂閱者就是Watcher。
  • Watcher:訂閱者作爲Observer和Compile之間通信的橋樑。在收到屬性變化的通知後,調用自身的更新函數,觸發Compile中綁定的回調函數。

  • Compile:主要做的事情是解析模板指令,將模板中的變量替換成數據,然後初始化渲染頁面視圖,並將每個指令對應的節點綁定更新函數,添加監聽數據的訂閱者,一旦數據有變動,收到通知,更新視圖。

虛擬 DOM 

虛擬DOM本質上就是一個普通的JavaScript對象,裏面能很好的表示DOM元素需要記錄的信息:節點名稱、屬性,文本,子節點等。比如下:

{
    // 節點類型
    type: 'ul',
    // 節點的屬性,包括dom原生屬性和自定義屬性
    props: {
        class: 'list',
        style: 'color:red;'
    },
    // 子節點數組
    // 子對象結構也是一樣,包含了type,props,children,沒有子節點的話就是普通文本
    // 子對象擁有子節點時,繼續往下擴展就行
    children: [
        {type: 'li',props: {class: 'list'},children: ['利羣']},
        {type: 'li',props: {class: 'list'},children: ['玉溪']},
        {type: 'li',props: {class: 'list'},children: ['黃鶴樓']}
    ]
}

虛擬DOM的必要性:

virtual-dom(後文簡稱vdom)的概念大規模的推廣還是得益於react出現,virtual-dom也是react這個框架的非常重要的特性之一。相比於頻繁的手動去操作dom而帶來性能問題,vdom很好的將dom做了一層映射關係,進而將在我們本需要直接進行dom的一系列操作,映射到了操作vdom,而vdom上定義了關於真實dom的一些關鍵的信息,vdom完全是用js去實現,和宿主瀏覽器沒有任何聯繫,此外得益於js的執行速度,將原本需要在真實dom進行的創建節點,刪除節點,添加節點等一系列複雜的dom操作全部放到vdom中進行,這樣就通過操作vdom來提高直接操作的dom的效率和性能。

Virtual DOM 算法實現的大致邏輯:

  • 用JavaScript對象結構DOM樹的結構,然後用這個結構構建成一個真正的DOM樹,並渲染到文檔中去。
  • 當JavaScript對象發生變化,則重新構建一顆新的對象樹,然後比較兩個對象樹,記錄兩棵樹之間的差別。
  • 把記錄的差別應用到步驟1所構建的DOM樹上,完成更新。

watcher與computed的區別

watcher:一個值影響多個值;監聽已有屬性;允許異步操作

computed:多個值影響一個值;生成一個新的屬性;不允許異步操作;必須有依賴型數據;當依賴數據發生變化纔會重新計算,否則用緩存;內部有getter和setter方法。

created與mounted的區別

主要的區別在於是否有渲染DOM樹。

  • beforeCreate:DOM節點、data、methods都不能獲取。
  • created:DOM節點不能獲取,data、methods可以獲取。
  • beforeMounted:DOM節點不能獲取,data、methods可以獲取。
  • mounted:DOM節點、data、methods都可以獲取。

v-for與v-if爲什麼避免一起使用

v-for的優先級高於v-if,所以v-if會執行在每一個v-for的子元素中,從而降低性能。

解決方法:

  • 將v-if置於v-for的上層
  • 將需要循環的屬性通過computed進行過濾,然後v-for循環computed屬性。

循環指令中,key值的作用

主要作用是用來提高虛擬DOM更新的效率,是在diff算法判斷中,用來判斷兩個節點是否相同的一個很重要的標準。

組件間的通信

  • 父傳子props,v-model,子傳父emit
  • 全局vuex,eventBus(Vue.prototype.bus = new Vue())

vue.use的用途及原理

use方法是用來擴展插件的。源碼如下(src/core/global-api/use.js):

export function initUse (Vue: GlobalAPI) {
  Vue.use = function (plugin: Function | Object) {
    const installedPlugins = (this._installedPlugins || (this._installedPlugins = []))
    // 如果當前plugin已經被use調用過了,則直接返回
    if (installedPlugins.indexOf(plugin) > -1) {
      return this
    }

    // additional parameters
    const args = toArray(arguments, 1)
    args.unshift(this)
    // 如果plugin對象中有install方法,則執行
    if (typeof plugin.install === 'function') {
      plugin.install.apply(plugin, args)
    // 如果plugin本身就是方法,則執行
    } else if (typeof plugin === 'function') {
      plugin.apply(null, args)
    }
    // 最後再將plugin緩存起來
    installedPlugins.push(plugin)
    return this
  }
}

vue.$nextTick方法的用途及原理

以下爲vue源碼(src/core/util/next-tick.js):

let timerFunc
// 如果有Promise且是原生API,則選用Promise(微任務)
if (typeof Promise !== 'undefined' && isNative(Promise)) {
  const p = Promise.resolve()
  timerFunc = () => {
    p.then(flushCallbacks)
    if (isIOS) setTimeout(noop)
  }
  isUsingMicroTask = true
  // 如果支持MutationObserver,則用MutationObserver(MutationObserver是用來監聽DOM變化的API,爲微任務)
} else if (!isIE && typeof MutationObserver !== 'undefined' && (
  isNative(MutationObserver) ||
  // PhantomJS and iOS 7.x
  MutationObserver.toString() === '[object MutationObserverConstructor]'
)) {
  let counter = 1
  const observer = new MutationObserver(flushCallbacks)
  const textNode = document.createTextNode(String(counter))
  observer.observe(textNode, {
    characterData: true
  })
  timerFunc = () => {
    counter = (counter + 1) % 2
    textNode.data = String(counter)
  }
  isUsingMicroTask = true
  // 如果支持setTmmediate,則用setTmmediate(可以看成setTimeout,兼容性不好,僅IE10+及nodejs支持,爲宏任務)
} else if (typeof setImmediate !== 'undefined' && isNative(setImmediate)) {
  timerFunc = () => {
    setImmediate(flushCallbacks)
  }
} else {
  // Fallback to setTimeout.
  // 最後的應急方案,setTimeout方法(宏任務)
  timerFunc = () => {
    setTimeout(flushCallbacks, 0)
  }
}

上面代碼分析得出,在vue被實例化執行的時候,首先判斷微任務(Promise > MutationObserver)是否支持,然後再判斷宏任務(setImmediate)是否支持,最後採用setTimeout方法。具體之間的區別可以查下JavaScript的事件循環,微任務與宏任務的區別。

mixin

Mixins 使我們能夠爲 Vue 組件編寫可插拔和可重用的功能。如果我們希望在多個組件間重用一組選項,比如data、computed、methods等,那麼我們可以將其寫成mixin,並在需要的地方引用它,然後通過mixin合併到當前組件。如果一個組件中有引入mixin,那麼mixin中的生命週期hook將優先組件自己內的hook。

vuex

Vuex 是一個專爲 Vue.js 應用程序開發的響應式狀態管理模式。它採用集中式存儲管理應用的所有組件的狀態,並以相應的規則保證狀態以一種可預測的方式發生變化。

規則:

  • 應用層級的狀態應該集中到單個 store 對象中。
  • 提交 mutation 是更改狀態的唯一方法,並且這個過程是同步的。
  • 異步邏輯都應該封裝到 action 裏面。

5個核心概念:

  • state:單一的狀態樹對象,包含了全部的應用層級狀態。可以簡單的理解爲整個狀態管理的倉庫地址,可以設置內部所有屬性的初始值,並且整個store狀態是響應式的,每當state內的屬性值改變,監視的vue組件也會同步更新。
  • mutation:提交 mutation是更改 Vuex 的 store 中的狀態的唯一方法,它是一個同步函數。
  • action:類似與mutation,不同的是action不能直接更改state,要通過提交mutation來更改。在action內可以執行任何異步任務,也可以通過dispath調用另一個action任務。
  • module:當項目很複雜的時候,我們可以使用module來進行模塊劃分。每個module內部都有自己的state,mutation,action,getter、對於模塊內部的 mutation 和 getter,接收的第一個參數是模塊的局部狀態對象、action內部使用的根節點爲context.rootState、getter使用的根節點爲第三個參數。默認情況下,模塊內部的state是註冊在全局命名空間的,如果有使用namespaced爲true,那麼在引用的時候,需要在前面加上模塊名稱,如(this.$store.dispath('moduleName/actionFunction()'))。
  • getter:可以認爲爲store的計算屬性,通過它可以對state狀態的值進行重新計算緩存並返回。

數據傳輸流程:

  • 在實例化Vuex.Store()的時候,創建一個全局倉庫state,並將內部屬性進行數據劫持。
  • state內部數據需要修改的時候需要遵循單項數據流,在組件中通過dispath方法調用action方法。
  • action內部方法處理完成後,然後再調用commit方法通知mutation。
  • mutation內部方法用來修改state中的數據。
  • state內部數據更改完成,因其數據爲響應式,則組件中依賴的值也會相應變化

 

未完待續......

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章