天天看點

vue基本原理和功能實作

知識儲備

  1. ​[].slice.call(lis)​

    ​: 将僞數組轉換為真數組
  2. ​node.nodeType​

    ​: 得到節點類型
  3. ​Object.defineProperty(obj, propertyName, {})​

    ​​: 給對象添加/修改屬性(指定描述符)

    configurable: true/false 是否可以重新​

    ​define​

    ​enumerable: true/false 是否可以枚舉​

    ​(for..in / keys())​

    ​value: 指定初始值

    writable: true/false ​

    ​value​

    ​是否可以修改存取(通路)描述符

    get: 函數, 用來得到目前屬性值

    set: 函數, 用來監視目前屬性值的變化

  4. ​Object.keys(obj)​

    ​: 得到對象自身可枚舉的屬性名的數組
  5. ​DocumentFragment​

    ​: 文檔碎片(高效批量更新多個節點)
  6. ​obj.hasOwnProperty(prop)​

    ​​: 判斷​

    ​prop​

    ​​是否是​

    ​obj​

    ​自身的屬性

資料代理(MVVM.js)

  1. 通過一個對象代理對另一個對象中屬性的操作(讀/寫)
  2. 通過​

    ​vm​

    ​​對象來代理​

    ​data​

    ​對象中所有屬性的操作
  3. 好處: 更友善的操作data中的資料
  4. 基本實作流程

    1). 通過​​

    ​Object.defineProperty()​

    ​​給​

    ​vm​

    ​​添加與​

    ​data​

    ​​對象的屬性對應的屬性描述符

    2). 所有添加的屬性都包含​​

    ​getter/setter​

    ​​ 3). 在​

    ​getter/setter​

    ​内部去操作​

    ​data​

    ​中對應的屬性資料

模闆解析(compile.js)

  1. 模闆解析的關鍵對象: ​

    ​compile​

    ​對象
  2. 模闆解析的基本流程:

    1). 将el的所有子節點取出, 添加到一個建立的文檔fragment對象中

    2). 對​​

    ​fragment​

    ​中的所有層次子節點遞歸進行編譯解析處理

    * 對表達式文本節點進行解析

    * 對元素節點的指令屬性進行解析

    * 事件指令解析

    * 一般指令解析

    3). 将解析後的​​

    ​fragment​

    ​​添加到​

    ​el​

    ​中顯示
  3. 解析表達式文本節點:​

    ​textNode.textContent = value​

    ​​ 1). 根據正則對象得到比對出的表達式字元串: 子比對​

    ​/RegExp.$1​

    ​ 2). 從data中取出表達式對應的屬性值

    3). 将屬性值設定為文本節點的textContent

  4. 事件指令解析: ​

    ​elementNode.addEventListener(事件名, 回調函數.bind(vm))​

    ​​

    ​v-on:click="test"​

    ​ 1). 從指令名中取出事件名

    2). 根據指令的值(表達式)從methods中得到對應的事件處理函數對象

    3). 給目前元素節點綁定指定事件名和回調函數的dom事件監聽

    4). 指令解析完後, 移除此指令屬性

  5. 一般指令解析: ​

    ​elementNode.xxx = value​

    ​​ 1). 得到指令名和指令值(表達式)

    2). 從data中根據表達式得到對應的值

    3). 根據指令名确定需要操作元素節點的什麼屬性

    * ​

    ​v-text---textContent​

    ​屬性

    * ​

    ​v-html---innerHTML​

    ​屬性

    * ​

    ​v-class--className​

    ​屬性

    4). 将得到的表達式的值設定到對應的屬性上

    5). 移除元素的指令屬性

資料劫持–>資料綁定

資料綁定(model==>View):

  1. 一旦更新了data中的某個屬性資料, 所有界面上直接使用或間接使用了此屬性的節點都會更新(更新)

資料劫持

四個重要對象

Observer

  1. 用來對​

    ​data​

    ​所有屬性資料進行劫持的構造函數
  2. 給​

    ​data​

    ​​中所有屬性重新定義屬性描述​

    ​(get/set)​

  3. 為​

    ​data​

    ​​中的每個屬性建立對應的​

    ​dep​

    ​對象

Dep(Depend)

  1. ​data​

    ​​中的每個屬性(所有層次)都對應一個​

    ​dep​

    ​對象
  2. 建立的時機:
  • 在初始化​

    ​define​

    ​​ ​

    ​data​

    ​中各個屬性時建立對應的dep對象
  • 在​

    ​data​

    ​中的某個屬性值被設定為新的對象時
  1. 對象的結構
{
   id, // 每個dep都有一個唯一的id
   subs //包含n個對應watcher的數組(subscribes的簡寫)
 }      
  1. ​subs​

    ​​屬性說明

    * 當一個​​

    ​watcher​

    ​​被建立時, 内部會将目前​

    ​watcher​

    ​​對象添加到對應的​

    ​dep​

    ​​對象的​

    ​subs​

    ​​中

    * 當此​​

    ​data​

    ​​屬性的值發生改變時, 所有​

    ​subs​

    ​​中的​

    ​watcher​

    ​都會收到更新的通知, 進而最終更新對應的界面

Compile

  1. 用來解析模闆頁面的對象的構造函數(一個執行個體)
  2. 利用​

    ​compile​

    ​對象解析模闆頁面
  3. 每解析一個表達式(非事件指令)都會建立一個對應的​

    ​watcher​

    ​​對象, 并建立​

    ​watcher​

    ​​與​

    ​dep​

    ​的關系
  4. ​complie​

    ​​與​

    ​watcher​

    ​關系: 一對多的關系

Watcher

  1. 模闆中每個非事件指令或表達式都對應一個​

    ​watcher​

    ​對象
  2. 監視目前表達式資料的變化
  3. 建立的時機: 在初始化編譯模闆時
  4. 對象的組成
{
   vm,  //vm對象
   exp, //對應指令的表達式
   cb, //當表達式所對應的資料發生改變的回調函數
   value, //表達式目前的值
   depIds //表達式中各級屬性所對應的dep對象的集合對象
           //屬性名為dep的id, 屬性值為dep
}      

總結: dep與watcher的關系: 多對多

  1. 一個​

    ​data​

    ​​中的屬性對應對應一個​

    ​dep​

    ​​, 一個​

    ​dep​

    ​​中可能包含多個​

    ​watcher​

    ​(模闆中有幾個表達式使用到了屬性)
  2. 模闆中一個非事件表達式對應一個​

    ​watcher​

    ​​, 一個​

    ​watcher​

    ​​中可能包含多個​

    ​dep​

    ​​(表達式中包含了幾個​

    ​data​

    ​屬性)
  3. 資料綁定使用到2個核心技術:

    * ​​

    ​defineProperty()​

    ​ * 消息訂閱與釋出

雙向資料綁定

  1. 雙向資料綁定是建立在單向資料綁定​

    ​(model==>View)​

    ​的基礎之上的
  2. 雙向資料綁定的實作流程:

    * 在解析​​

    ​v-model​

    ​​指令時, 給目前元素添加​

    ​input監聽​

    ​​ * 當​

    ​input​

    ​的​

    ​value​

    ​發生改變時, 将最新的值指派給目前表達式所對應的​

    ​data屬性​

繼續閱讀