3744-4498 行:virtual dom 渲染算法实现,提供 diff apply render 等方法,该模块接口基本与 virtual-dom 一致,这里特别的地方在于它所 diff 和生成的并不是原生 DOM,而是各种模拟了 DOM 接口的 wx element 对象
4599-4510 行:插入默认样式到页面
从页面 data 到 dom 的主要流程如下:
var vtree
var rootNode
document.addEventListener("generateFuncReady", function(e) {
var generateFunc = e.detail.generateFunc;
wx.onAppDataChange(function(obj) {
// 合并 data 到现有 data
DataStore.setData(obj.data)
// 生成 virtual dom 的 javascript plain object
var props = generateFunc(DataStore.getData())
// 第一次渲染
if (obj.options.firstRender) {
vtree = createVirtualTree(props, true)
rootNode = vtree.render()
rootNode.replaceDocumentElement(document.body)
wx.initReady()
} else {
var other_vtree = createVirtualTree(props, false)
var patches = vtree.diff(other_vtree)
patches.apply(rootNode)
vtree = other_vtree
document.dispatchEvent(new CustomEvent("pageReRender", {}));
}
})
})
上面的 DataStore 对象提供合并和获取当前页面 data 对象的功能,其实现如下:
var DataStore = (function() {
var data = {}
return {
getData: function() {
return data
},
setData: function(e) {
for (var t in e) {
for (var n = (0, parsePath)(t), o = data, a = void 0, s = void 0, c = 0; c < n.length; c++) Number(n[c]) === n[c] && Number(n[c]) % 1 === 0 ? Array.isArray(o) || (a[s] = [], o = a[s]) : "[object Object]" !== Object.prototype.toString.call(o) && (a[s] = {}, o = a[s]), s = n[c], a = o, o = o[n[c]];
a && (a[s] = e[t])
}
}
}
})()
// 解析 key 为 data 内对象的路径字符串
function parsePath(e) {
for (var t = e.length, n = [], i = "", r = 0, o = !1, a = !1, s = 0; s < t; s++) {
var c = e[s];
if ("" === c) s + 1 < t && ("." === e[s + 1] || "[" === e[s + 1] || "]" === e[s + 1]) ? (i += e[s + 1], s++) : i += "";
else if ("." === c) i && (n.push(i), i = "");
else if ("[" === c) {
if (i && (n.push(i), i = ""), 0 === n.length) throw new Error("path can not start with []: " + e);
a = !0, o = !1
} else if ("]" === c) {
if (!o) throw new Error("must have number in []: " + e);
a = !1, n.push(r), r = 0
} else if (a) {
if (c < "0" || c > "9") throw new Error("only number 0-9 could inside []: " + e);
o = !0, r = 10 * r + c.charCodeAt(0) - 48
} else i += c
}
if (i && n.push(i), 0 === n.length) throw new Error("path can not be empty");
return n
}