1. 準(zhǔn)備
1.[].slice.call(lis): 將偽數(shù)組轉(zhuǎn)換為真數(shù)組
2.node.nodeType: 得到節(jié)點類型
3.Object.defineProperty(obj, propertyName, {}): 給對象添加/修改屬性(指定描述符)
configurable: true/false 是否可以重新define
enumerable: true/false 是否可以枚舉(for..in / keys())
value: 指定初始值
writable: true/false value是否可以修改存取(訪問)描述符
get: 函數(shù), 用來得到當(dāng)前屬性值
set: 函數(shù), 用來監(jiān)視當(dāng)前屬性值的變化
4.Object.keys(obj): 得到對象自身可枚舉的屬性名的數(shù)組
5.DocumentFragment: 文檔碎片(高效批量更新多個節(jié)點)
6.obj.hasOwnProperty(prop): 判斷prop是否是obj自身的屬性
2. 數(shù)據(jù)代理(MVVM.js)
1.通過一個對象代理對另一個對象中屬性的操作(讀/寫)
2.通過vm對象來代理data對象中所有屬性的操作
3.好處: 更方便的操作data中的數(shù)據(jù)
4.基本實現(xiàn)流程
1). 通過Object.defineProperty()給vm添加與data對象的屬性對應(yīng)的屬性描述符
2). 所有添加的屬性都包含getter/setter
3). 在getter/setter內(nèi)部去操作data中對應(yīng)的屬性數(shù)據(jù)
3. 模板解析(compile.js)
1.模板解析的關(guān)鍵對象: compile對象
2.模板解析的基本流程:
1). 將el的所有子節(jié)點取出, 添加到一個新建的文檔fragment對象中
2). 對fragment中的所有層次子節(jié)點遞歸進行編譯解析處理
* 對表達式文本節(jié)點進行解析
* 對元素節(jié)點的指令屬性進行解析
* 事件指令解析
* 一般指令解析
3). 將解析后的fragment添加到el中顯示
3.解析表達式文本節(jié)點: textNode.textContent = value
1). 根據(jù)正則對象得到匹配出的表達式字符串: 子匹配/RegExp.$1
2). 從data中取出表達式對應(yīng)的屬性值
3). 將屬性值設(shè)置為文本節(jié)點的textContent
4.事件指令解析: elementNode.addEventListener(事件名, 回調(diào)函數(shù).bind(vm))
v-on:click="test"
1). 從指令名中取出事件名
2). 根據(jù)指令的值(表達式)從methods中得到對應(yīng)的事件處理函數(shù)對象
3). 給當(dāng)前元素節(jié)點綁定指定事件名和回調(diào)函數(shù)的dom事件監(jiān)聽
4). 指令解析完后, 移除此指令屬性
5.一般指令解析: elementNode.xxx = value
1). 得到指令名和指令值(表達式)
2). 從data中根據(jù)表達式得到對應(yīng)的值
3). 根據(jù)指令名確定需要操作元素節(jié)點的什么屬性
* v-text---textContent屬性
* v-html---innerHTML屬性
* v-class--className屬性
4). 將得到的表達式的值設(shè)置到對應(yīng)的屬性上
5). 移除元素的指令屬性
4. 數(shù)據(jù)劫持-->數(shù)據(jù)綁定
1.數(shù)據(jù)綁定(model==>View):
1). 一旦更新了data中的某個屬性數(shù)據(jù), 所有界面上直接使用或間接使用了此屬性的節(jié)點都會更新(更新)
2.數(shù)據(jù)劫持
1). 數(shù)據(jù)劫持是vue中用來實現(xiàn)數(shù)據(jù)綁定的一種技術(shù)
2). 基本思想: 通過defineProperty()來監(jiān)視data中所有屬性(任意層次)數(shù)據(jù)的變化, 一旦變化就去更新界面
3.四個重要對象
1). Observer
* 用來對data所有屬性數(shù)據(jù)進行劫持的構(gòu)造函數(shù)
* 給data中所有屬性重新定義屬性描述(get/set)
* 為data中的每個屬性創(chuàng)建對應(yīng)的dep對象
2). Dep(Depend)
* data中的每個屬性(所有層次)都對應(yīng)一個dep對象
* 創(chuàng)建的時機:
* 在初始化define data中各個屬性時創(chuàng)建對應(yīng)的dep對象
* 在data中的某個屬性值被設(shè)置為新的對象時
* 對象的結(jié)構(gòu)
{
id, // 每個dep都有一個唯一的id
subs //包含n個對應(yīng)watcher的數(shù)組(subscribes的簡寫)
}
* subs屬性說明
* 當(dāng)一個watcher被創(chuàng)建時, 內(nèi)部會將當(dāng)前watcher對象添加到對應(yīng)的dep對象的subs中
* 當(dāng)此data屬性的值發(fā)生改變時, 所有subs中的watcher都會收到更新的通知, 從而最終更新對應(yīng)的界面
3). Compile
* 用來解析模板頁面的對象的構(gòu)造函數(shù)(一個實例)
* 利用compile對象解析模板頁面
* 每解析一個表達式(非事件指令)都會創(chuàng)建一個對應(yīng)的watcher對象, 并建立watcher與dep的關(guān)系
* complie與watcher關(guān)系: 一對多的關(guān)系
4). Watcher
* 模板中每個非事件指令或表達式都對應(yīng)一個watcher對象
* 監(jiān)視當(dāng)前表達式數(shù)據(jù)的變化
* 創(chuàng)建的時機: 在初始化編譯模板時
* 對象的組成
{
vm, //vm對象
exp, //對應(yīng)指令的表達式
cb, //當(dāng)表達式所對應(yīng)的數(shù)據(jù)發(fā)生改變的回調(diào)函數(shù)
value, //表達式當(dāng)前的值
depIds //表達式中各級屬性所對應(yīng)的dep對象的集合對象
//屬性名為dep的id, 屬性值為dep
}
5). 總結(jié): dep與watcher的關(guān)系: 多對多
* 一個data中的屬性對應(yīng)對應(yīng)一個dep, 一個dep中可能包含多個watcher(模板中有幾個表達式使用到了屬性)
* 模板中一個非事件表達式對應(yīng)一個watcher, 一個watcher中可能包含多個dep(表達式中包含了幾個data屬性)
* 數(shù)據(jù)綁定使用到2個核心技術(shù)
* defineProperty()
* 消息訂閱與發(fā)布
4.雙向數(shù)據(jù)綁定
1). 雙向數(shù)據(jù)綁定是建立在單向數(shù)據(jù)綁定(model==>View)的基礎(chǔ)之上的
2). 雙向數(shù)據(jù)綁定的實現(xiàn)流程:
* 在解析v-model指令時, 給當(dāng)前元素添加input監(jiān)聽
* 當(dāng)input的value發(fā)生改變時, 將最新的值賦值給當(dāng)前表達式所對應(yīng)的data屬性