1.創建虛擬節點的類,這裏使用es6語法糖。
export default class VNode {
constructor(
// 節點類型和標籤類型的區別是什麼?
tag, // 標籤類型,DIV,SPAN,INPUT,#text
ele, // 對應的真實節點
children, // 當前節點下的子節點
text, // 當前虛擬節點的文本
data, // VNodeData,暫時保留,暫無意義
parent, // 父級節點
nodeType, // 節點類型
) {
this.tag = tag;
this.ele = ele;
this.children = children;
this.text = text;
this.data = data;
this.parent = parent;
this.nodeType = nodeType;
this.env = {}; // 當前節點的環境變量,這個是自己設定的
this.instructions = null; // 存放指令的
this.template = []; // 當前節點涉及到的模板
}
}
2.構建虛擬DOM樹並且掛載到Vue上,使用深度先搜索構建虛擬DOM樹。
import VNode from "../vnode/vnode.js";
export function initMount(Vue) {
Vue.prototype.$mount = function (el) {
let vm = this;
let rootDom = document.getElementById(el);
mount(vm, rootDom);
}
}
export function mount(vm, ele) {
// 進行掛載
vm._vnode = constructVNode(vm, ele, null);
// 進行預備渲染(簡歷渲染索引,通過模板找vnode,通過vnode找模板)
}
function constructVNode(vm, ele, parent) {
let vnode = null;
let children = [];
let text = getNodeText(ele); // 不確定是否有文本,只有文本節點纔有文本
let data = null;
let nodeType = ele.nodeType;
let tag = ele.nodeName;
vnode = new VNode(tag, ele, text, data, parent, nodeType);
// 獲取子節點
let childs = vnode.ele.childNodes;
// 深度優先算法DFS
for (let i = 0; i < childs.length; i++) {
let childNode = constructVNode(vm, childs[i], vnode);
if (childNode instanceof VNode) { // 返回單一節點的時候
vnode.children.push(childNode);
} else { // 返回節點數組
vnode.children = vnode.children.concat(childNode);
}
}
return vnode;
}
function getNodeText(ele) {
if (ele.nodeType === 3) { // 標籤類型爲#TEXT時
return ele.nodeValue;
} else {
return '';
}
}