Vue原理解析:手寫編譯器(節點解析) —— Compile
由於時間問題,暫時先把程式碼完整的貼上來,感興趣的朋友可以自行研究或收藏。等我那時有時間的時候,對專欄文章進行排序,並逐一講解程式碼
一、宣告式HTML
<div id="app">
<h3>Hello,{{personName}},你在{{msg}}嗎?</h3>
<div v-text="msg" v-on:click="handleShowTip"></div>
<div v-text="msg" @click="handleShowMsg(msg, personName)"></div>
<div v-html="htmlStr"></div>
</div>
<script src="src/MVue.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
let vm = new MVue({
el: "#app",
data: {
msg: "學習MVVM原理",
htmlStr: "<h4>你學的怎麼樣?</h4>",
personName: "張三",
test: {
name: "張三"
}
},
methods: {
handleShowMsg(key) {
this.msg = "hhx";
},
handleShowTip() {
console.log(this);
}
}
})
</script>
二、編譯器處理例項
class Compile {
constructor(el, vm) {
this.vm = vm;
this.el = this.isElementNode(el) ? el : document.querySelector(el);
// 1.獲取文件碎片物件,放入記憶體中會減少頁面的迴流和重繪
const fragment = this.node2Fragment(this.el);
// 2.編譯模板
this.compile(fragment);
// 3.追加子元素到根元素
this.el.appendChild(fragment)
}
compile(fragment) {
// 1.獲取子節點
const childNodes = fragment.childNodes;
childNodes.forEach(child => {
if (this.isElementNode(child)) {
// 編譯元素節點
this.compileElement(child);
} else {
// 編譯文字節點
this.compileText(child);
}
if (child.childNodes && child.childNodes.length) {
this.compile(child);
}
})
}
compileText(node) {
const content = node.textContent;
if (/\{\{(.+?)\}\}/.test(content)) {
compileUntil["text"](node, content, this.vm);
}
}
compileElement(node) {
const attrs = node.attributes;
[...attrs].forEach((attr) => {
const {
name,
value
} = attr;
console.log(attr);
if (this.isDirective(name)) {
const [, diractive] = name.split("-");
const [dirName, eventName] = diractive.split(":");
// 更新資料,資料驅動檢視
compileUntil[dirName](node, value, this.vm, eventName);
// 刪除標籤上的指令
node.removeAttribute("v-" + diractive);
}
if (this.isEvent(name)) {
const [, eventName] = name.split("@");
compileUntil["on"](node, value, this.vm, eventName);
}
});
}
isEvent(attrName) {
return attrName.startsWith("@");
}
isDirective(attrName) {
return attrName.startsWith("v-");
}
node2Fragment(el) {
// 建立文件碎片
const f = document.createDocumentFragment();
let firstChild;
while (firstChild = el.firstChild) {
f.appendChild(firstChild);
}
return f;
}
isElementNode(node) {
return node.nodeType === 1
}
}
三、編譯器解析工具
const compileUntil = {
getValue(expr, vm) {
// 切分物件屬性,不斷的累加到目的屬性
return expr.split(".").reduce((data, currentVal) => {
return data[currentVal];
}, vm.$data);
},
text(node, expr, vm) {
let value;
// 判斷是否存在變數引數, 如果存在則將變數物件值替換掉宣告變數
if (expr.indexOf("{{") !== -1) {
value = expr.replace(/\{\{(.+?)\}\}/g, (...args) => {
return this.getValue(args[1], vm);
});
} else {
value = this.getValue(expr, vm);
}
// 更新檢視
this.updater.textUpdater(node, value);
},
html(node, expr, vm) {
const value = this.getValue(expr, vm);
this.updater.htmlUpdater(node, value);
},
model(node, expr, vm) {
const value = this.getValue(expr, vm);
this.updater.modelUpdater(node, value);
},
bind(node, expr, vm, attrName) {
},
on(node, expr, vm, eventName) {
let param = [];
let fnName = expr.replace(/\((.+?)\)/g, (...args) => {
param = args[1].split(",");
return "";
});
let fn = vm.$options.methods && vm.$options.methods[fnName];
node.addEventListener(eventName, fn.bind(vm, ...param), false);
},
updater: {
textUpdater(node, value) {
node.textContent = value;
},
htmlUpdater(node, value) {
node.innerHTML = value;
},
modelUpdater(node, value) {
node.value = value;
}
}
}
相關文章
- 工程中的編譯原理 -- Mapfile解析器編譯原理
- 手寫 Vue2 系列 之 編譯器Vue編譯
- 一張圖解析 編譯器編譯流程圖解編譯
- Vue 原始碼解讀(8)—— 編譯器 之 解析(下)Vue原始碼編譯
- Vue 原始碼解讀(8)—— 編譯器 之 解析(上)Vue原始碼編譯
- 手寫一個解析器
- Vue.js 模板解析器原理Vue.js
- Vue原始碼模板編譯階段----HTML解析器腦圖Vue原始碼編譯HTML
- 手寫javascript json解析器JavaScriptJSON
- 為 man 手冊頁編寫解析器的備忘錄
- 基本功 | Java即時編譯器原理解析及實踐Java編譯
- Vue.js 1.0 的 DOM 編譯過程解析Vue.js編譯
- Vue 模板編譯原理Vue編譯原理
- 簡易表示式解析器編寫
- 從AST編譯解析談到寫babel外掛AST編譯Babel
- Vue檢視渲染原理解析,從構建VNode到生成真實節點樹Vue
- vue之mvvm原理解析VueMVVM
- 精讀《手寫SQL編譯器-回溯》SQL編譯
- vue編譯器Vue編譯
- 手寫Json解析器學習心得JSON
- Unity 編譯 Android 的原理解析和 apk 打包分析Unity編譯AndroidAPK
- 深入解析vue響應式原理Vue
- 深度解析 Vue 響應式原理Vue
- C語言編譯器開發之旅(二):解析器C語言編譯
- vue模板編譯(原理篇)Vue編譯
- 編譯deno,deno結構解析編譯
- 模仿vue自己動手寫響應式框架(三) - dom解析Vue框架
- 前端與編譯原理——用 JS 寫一個 JS 直譯器前端編譯原理JS
- 前端與編譯原理——用JS寫一個JS直譯器前端編譯原理JS
- 精讀《手寫 SQL 編譯器 – 詞法分析》SQL編譯詞法分析
- 精讀《手寫 SQL 編譯器 - 語法樹》SQL編譯
- 精讀《手寫 SQL 編譯器 - 錯誤提示》SQL編譯
- 精讀《手寫 SQL 編譯器 - 語法分析》SQL編譯語法分析
- 精讀《手寫 SQL 編譯器 - 文法介紹》SQL編譯
- 精讀《手寫 SQL 編譯器 – 文法介紹》SQL編譯
- 精讀《手寫 SQL 編譯器 - 詞法分析》SQL編譯詞法分析
- 瀏覽器原理解析瀏覽器
- Python使用Mechanize模組編寫爬蟲的要點解析Python爬蟲