模板解析
模板:就是html嵌套js代碼,js代碼以兩種形式存在于頁(yè)面里浅浮,指令屬性和表達(dá)式
模板解析大括號(hào)表達(dá)式{{}}的基本流程:
1沫浆、將el的所有子節(jié)點(diǎn)取出,添加到一個(gè)新建的文檔fragement對(duì)象中滚秩。
2专执、對(duì)fragement中的所有層次子節(jié)點(diǎn)遞歸進(jìn)行編譯解析處理。
3叔遂、通過(guò)nodeType判斷節(jié)點(diǎn)是元素節(jié)點(diǎn)還是文本節(jié)點(diǎn)
4他炊、如果是元素節(jié)點(diǎn)根據(jù)正則表達(dá)式得到匹配出的表達(dá)式字符串。/{{(.+?)}}/g
5已艰、從data中取出表達(dá)式對(duì)應(yīng)的屬性值
6痊末、將屬性值設(shè)置為文本節(jié)點(diǎn)的textContent
7、將解析后的fragement添加到el中
虛擬DOM
為什么要使用虛擬DOM哩掺?
因?yàn)樘岣咝阅茉涞H绻苯釉陧?yè)面當(dāng)中去操作DOM頁(yè)面要不斷的更新,很消耗性能嚼吞,使用虛擬DOM所有的操作都在內(nèi)存里面盒件,只需要虛擬DOM的處理完成了更新到頁(yè)面上只用更新一次。
虛擬DOM是一個(gè)對(duì)象
1舱禽、怎么將真正的DOM轉(zhuǎn)換為虛擬DOM炒刁?
<div id="root">
<div>hello</div>
</div>
<script>
class VNode {
constructor(tag, data, value, type){
this.tag = tag && tag.toLowerCase()
this.data = data
this.value = value
this.type = type
this.children = []
}
appendChild (vnode) {
this.children.push(vnode)
}
}
//使用遞歸來(lái)遍歷DOM元素,生成虛擬DOM
function getVNode(node) {
let nodeType = node.nodeType
let _vnode = null
if (nodeType === 1) { //元素
let nodeName = node.nodeName
let attrs = node.attributes
let _attrsObj = {}
for (let i = 0; i < attrs.length; i++) { //attrs[i]屬性節(jié)點(diǎn) (nodeType===2)
_attrsObj[attrs[i].nodeName] = attrs[i].nodeValue
}
_vnode = new VNode(nodeNamw, _attrsObj, undefined, nodeType)
//考慮node的子元素
let childNodes = node.childNodes
for (let i = 0; i < childNodes .length; i++) {
_vnode.appendChild (getVNode(childNodes [i])) //遞歸
}
} else if (nodeType === 3) {
_vnode = new VNode(undefined, undefined, node.nodeValue, nodeType)
}
return _vnode
}
let root = document.querySelector('#root')
let vroot = getVNode(root)
console.log(vroot)
</script>
2誊稚、怎么將虛擬DOM轉(zhuǎn)換為真正的DOM翔始?
function parseVNode (vnode) {
//創(chuàng)建真實(shí)的DOM
let type= vnode.type
let _node = null
if (type === 3) {
return document.createTextNode(vnode.value) //創(chuàng)建文本節(jié)點(diǎn)
} else if (type === 1) {
_node = document.createElement(vnode.tag)
//處理屬性
let data = vnode.data
Object.keys(data).forEach(key => {
let attrName = key
let attrValue = data[key]
_node.setAttribute(attrName ,attrValue)
})
//處理子元素
let children = vnode.children
children .forEach(subnode => {
_node.appendChild (parseVNode(subnode )) //遞歸轉(zhuǎn)換子元素 (是一個(gè)虛擬DOM)
})
return _node
}
}
let dom2 = parseVNode(vroot)
console.log(dom2)