模板解析
模板:就是html嵌套js代码,js代码以两种形式存在于页面里,指令属性和表达式
模板解析大括号表达式{{}}的基本流程:
1、将el的所有子节点取出,添加到一个新建的文档fragement对象中。
2、对fragement中的所有层次子节点递归进行编译解析处理。
3、通过nodeType判断节点是元素节点还是文本节点
4、如果是元素节点根据正则表达式得到匹配出的表达式字符串。/{{(.+?)}}/g
5、从data中取出表达式对应的属性值
6、将属性值设置为文本节点的textContent
7、将解析后的fragement添加到el中
虚拟DOM
为什么要使用虚拟DOM?
因为提高性能。如果直接在页面当中去操作DOM页面要不断的更新,很消耗性能,使用虚拟DOM所有的操作都在内存里面,只需要虚拟DOM的处理完成了更新到页面上只用更新一次。
虚拟DOM是一个对象
1、怎么将真正的DOM转换为虚拟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)
}
}
//使用递归来遍历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]属性节点 (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转换为真正的DOM?
function parseVNode (vnode) {
//创建真实的DOM
let type= vnode.type
let _node = null
if (type === 3) {
return document.createTextNode(vnode.value) //创建文本节点
} 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 )) //递归转换子元素 (是一个虚拟DOM)
})
return _node
}
}
let dom2 = parseVNode(vroot)
console.log(dom2)