1.vue虚拟DOM的作用
- 具备跨平台的优势
由于 Virtual DOM 是以 JavaScript 对象为基础而不依赖真实平台环境,所以使它具有了跨平台的能力,比如说浏览器平台、Weex、Node 等。
- 操作 DOM 慢,js运行效率高。我们可以将DOM对比操作放在JS层,提高效率。
因为DOM操作的执行速度远不如Javascript的运算速度快,因此,把大量的DOM操作搬运到Javascript中,运用patching算法来计算出真正需要更新的节点,最大限度地减少DOM操作,从而显著提高性能。
Virtual DOM 本质上就是在 JS 和 DOM 之间做了一个缓存。可以类比 CPU 和硬盘,既然硬盘这么慢,我们就在它们之间加个缓存:既然 DOM 这么慢,我们就在它们 JS 和 DOM 之间加个缓存。CPU(JS)只操作内存(Virtual DOM),最后的时候再把变更写入硬盘(DOM)
- 提升渲染性能
Virtual DOM的优势不在于单次的操作,而是在大量、频繁的数据更新下,能够对视图进行合理、高效的更新。
为了实现高效的DOM操作,一套高效的虚拟DOM diff算法显得很有必要。我们通过patch 的核心----diff 算法,找出本次DOM需要更新的节点来更新,其他的不更新。比如修改某个model 100次,从1加到100,那么有了Virtual DOM的缓存之后,只会把最后一次修改patch到view上。
2.模拟实现虚拟DOM
VN虚拟dom:把html这个结构(名称,样式,属性等)转换成一个jsduixiang ,通过操作js对象操作虚拟dom。
怎么操作虚拟dom实现页面更新渲染:页面在初次渲染的时候,把页面html结构(DOM树 )转换成一个js对象,如果页面再有更新的时候,把更新之后的虚拟dom的js对象和之前的虚拟dom对象进行对比。通过vue提供的diff算法,找到需要更新的节点,针对需要更新的节点进行局部更新,提高渲染效率。
代码如下:
<body>
<!-- VN虚拟dom:把html这个结构(名称,样式,属性等)转换成一个jsduixiang ,通过操作js对象操作虚拟dom -->
<!-- 怎么操作虚拟dom实现页面更新渲染:页面在初次渲染的时候,把页面html结构(DOM树 )转换成一个js对象,如果页面再有更新的时候,把更新之后的虚拟dom的js对象和之前的虚拟dom对象进行对比。通过vue提供的diff算法,找到需要更新的节点,针对需要更新的节点进行局部更新,提高渲染效率 -->
<div id="app">
<button>点击更新年龄</button>
<ul>
<li>{{name}}</li>
<li>{{age}}</li>
<li>{{phone}}</li>
</ul>
</div>
</body>
<script src="../vue.js"></script>
<script>
// 模拟虚拟dom更新的过程
var app = new Vue({
// el:"#app", 需要注释这句,
data: {
name: "张三",
age: 20,
phone: 110
},
// 1.先初次获取DOM结构,用来去模拟el:"#app"
created() {
// 用原生的dom操作来获取dom结构
var appHtml = document.getElementById("app")
var tempData = appHtml.innerHTML
// 把html结构里面的{{}}替换成data数据
tempData = tempData.replace("{{name}}", this.name)
// replace() 替换原字符串的部分字符,原字符串不会改变的
tempData = tempData.replace("{{age}}", this.age)
tempData = tempData.replace("{{phone}}", this.phone)
appHtml.innerHTML = tempData
var btn = document.querySelector("#app button")
btn.addEventListener("click", this.update)
// 2.把初次获取dom结构转换成虚拟dom对象
this.VN = {
type: "div", //type代表的是元素的名称
id: "app", // 把div的id属性转换成对象
children: [ // children 元素的子元素
{
type: "button",
content: "点击更新年龄",// content标签内容
event: { //event 事件
name: "click",//事件名称
fun: this.update //事件函数
}
},
{
type: "ul",
children: [
{
type: "li",
content: this.name
},
{
type: "li",
content: this.age
},
{
type: "li",
content: this.phone
}
]
}
]
}
},
methods: {
update() {
// 3.更新数据并且生成新的虚拟dom对象
this.age = 40
this.newVN = {
type: "div", //type代表的是元素的名称
id: "app", // 把div的id属性转换成对象
children: [ // children 元素的子元素
{
type: "button",
content: "点击更新年龄",// content标签内容
event: { //event 事件
name: "click",//事件名称
fun: this.update //事件函数
}
},
{
type: "ul",
children: [
{
type: "li",
content: this.name
},
{
type: "li",
content: this.age
},
{
type: "li",
content: this.phone
}
]
}
]
}
console.log(this.VN,this.newVN);
// 4.把更新之前的虚拟dom对象和更新之后的虚拟dom对象进行对比,通过diff算法进行对比,返回需要更新的节点
function diff(oldVN,newVN){
return [{
path:"#app>ul>li:nth-child(2)",
value:this.age
}]
}
// 5.遍历所有需要更新的对象,然后针对性的去更新dom节点
for (const obj of diff.call(this)) {
// 实现局部的更新
document.querySelector(obj.path).innerHTML = obj.value
}
}
},
})
</script>