看了某站上面的视频,做一个学习记录
compiler.html
代码复制在F12控制台可看见原始DOM、虚拟DOM、以及编译成功的真实DOM
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<script src="./compiler.js"></script>
<body>
<div id="app" title="66">
<div class="a1">
<div class="a2">{{user.name}}</div>
<div>{{user.age}}</div>
<div>{{user.ah.yy}}</div>
</div>
<div>{{flag}}</div>
<div>{{age}}</div>
</div>
<script>
// vue数据驱动
class SMVue {
constructor(options) {
this._virtualDOM = getDomByVirtualDOM(document.querySelector(options.el))
this.el = this.domTemp = document.querySelector(options.el)
this.data = options.data()
this.render()
}
render(){
this.compiler()
}
compiler(){
console.log("原始dom",this.el) // 原始dom
console.log("生成的虚拟dom",this._virtualDOM) // 基于原始dom 生成的虚拟dom
let temp = getVirtualDOMByDom(this._virtualDOM,this.data)
console.log('虚拟dom编译生成真实DOM',temp) // 虚拟dom 编译后生成的 真实dom
this.update(temp) // 更新挂载
}
update(temp){
this.domTemp.parentNode.replaceChild(temp,this.domTemp)
}
}
let vm = new SMVue({
el:"#app",
data () {
return {
user:{
name:"昭阳",
age:"25",
ah:{
yy:"游泳"
}
},
age:55,
flag:true
}
}
})
</script>
</body>
</html>
compiler.js 虚拟DOM的主要逻辑
let kuohaoFiler = /\{\{(.+>?)\}\}/g // 把{{name}} 分解成name
// 虚拟dom
class VNode {
constructor(tag,type,data,value){
this.tag = tag && tag.toLowerCase()
this.type = type
this.data = data
this.value = value
this.children = []
}
appendChild(vnode){
this.children.push(vnode)
}
}
// 废弃函数 - 这个模板的逻辑已经写在 getVirtualDOMByDom
function getTmepByCompiler (node, data) {
let nodes = node.childNodes
nodes.forEach(item => {
if (item.nodeType === 1) {
this.getTmepByCompiler(item, data)
} else if (item.nodeType === 3) {
let txt = item.nodeValue
txt.replace(kuohaoFiler, (_, g) => {
item.nodeValue = getDeepAnalysis(g, data)
})
}
});
return node
}
// dom转换成虚拟dom
function getDomByVirtualDOM (node) {
let nodeType = node.nodeType
let nodeName = node.nodeName
let nodeValue = node.nodeValue
let virtuaDom = {}
if (nodeType === 1) { // 元素节点
let attrs = node.attributes // 获取元素身上的属性 id title等
let attrsObj = {}
for (let i = 0; i < attrs.length; i++) {
attrsObj[attrs[i].nodeName] = attrs[i].nodeValue
}
virtuaDom = new VNode(nodeName, nodeType, attrsObj, nodeValue)
// 如果有子元素的情况
let nodes = node.childNodes
nodes.forEach(ele => {
virtuaDom.appendChild(getDomByVirtualDOM(ele))
});
} else if (nodeType === 3) { // 文本节点
virtuaDom = new VNode(undefined, nodeType, undefined, nodeValue)
}
return virtuaDom
}
// 把虚拟DOM转换成DOM
function getVirtualDOMByDom (vnode, createData) {
let { type, tag, value, data, children } = vnode
let _dom = null
if (type === 1) {
_dom = document.createElement(tag)
for (const key in data) {
_dom.setAttribute(key, data[key]) // data 数据通过setAttribute绑定到元素身上
}
children.forEach(element => {
_dom.appendChild(getVirtualDOMByDom(element, createData))
});
} else if (type === 3) {
value = value.replace(kuohaoFiler, (_, g) => {
return getDeepAnalysis(g, createData)
})
_dom = document.createTextNode(value)
}
return _dom
}
// 解析a.b.c.d 实际是string 转obj
function getDeepAnalysis (path, data) {
path = path.split('.')
for (let i = 0; i < path.length; i++) {
data = data[path[i]]
}
return data
}