實(shí)現(xiàn) MVVM 類 Vue 迷你框架(五)
如何實(shí)現(xiàn) MVVM 類 Vue 迷你框架(五)
上面幾節(jié)課我們已經(jīng)把數(shù)據(jù)代理,響應(yīng)式處理搞完了,接下來需要做什么呢?當(dāng)然是最難的一部分了,就是我們的編譯模板。
使用到的dom編程方法
element.childNodes - 返回元素子節(jié)點(diǎn)的 NodeList(可直接使用forEach遍歷),換行和空格會被識別成文本節(jié)點(diǎn)。 element.nodeType - 返回元素的節(jié)點(diǎn)類型,元素節(jié)點(diǎn)為 1,文本節(jié)點(diǎn)為 3 element.nodeName - 返回元素的名稱,例如**“DIV”** element.textContent - 設(shè)置或返回節(jié)點(diǎn)及其后代的文本內(nèi)容 element.attributes - 指定節(jié)點(diǎn)的屬性Attr(含有name和value屬性)合 NamedNodeMap(不可直接遍歷)
我們需要做什么呢?
拿到我們需要的 DOM 元素 然后需要解析 {{}}模板插值解析 m-text指令解析 m-html指令
所以我們需要一個(gè)編譯模板 Compile 類:
class Compile {
constructor(el, vm) {
this.$el = document.querySelector(el);
this.$vm = vm;
// 判斷是否存在 el
if(this.$el) {
this.compile(this.$el);
}
}
}
判斷節(jié)點(diǎn)是不是具有 {{}} 文本節(jié)點(diǎn)
class Compile {
constructor{
// ...
}
isInter(node) {
return node.nodeType === 3 && /{{.*}}/.test(node.textContent);
}
}
接下來我們封裝一個(gè)用于更新指令的公用方法:
update(node, key, dir) {
const fn = this[dir+'Updater']; // 查找指令方法
fn && fn(node, this.$vm[key];
// 更新
new Watcher(this.$vm, key, val => {
fn && fn(node, key)
})
}
如果是文本內(nèi)容我們就只更新文本:
textUpdater(node, val) {
node.textContent = val
}
text(node, key) {
this.update(node, key, 'text')
}
如果是 html 內(nèi)容就只更新 htm 內(nèi)容:
htmlUpdater(node, val) {
node.innerHTML = val
}
html(node, key) {
this.update(node, key, 'html');
}
模板插值解析:
compileText(node) {
this.update(node, RegExp.$1, 'text')
}
最后就是實(shí)現(xiàn) compile(node) 方法:
// 遞歸傳入節(jié)點(diǎn),根據(jù)節(jié)點(diǎn)類型做不同操作
compile(el) {
// 拿到子節(jié)點(diǎn)
const childNodes = el.childNodes;
childNodes.forEach(node => {
if (node.nodeType === 1) {
console.log('元素節(jié)點(diǎn)', node.nodeName);
} else if (this.isInter(node)) {
this.compileText(node);
console.log('文本節(jié)點(diǎn)', node.textContent);
}
if (node.childNodes) {
this.compile(node);
}
});
}
評論
圖片
表情
