前言
距离上一篇源码学习已经很长时间了,一件事情一旦放下了,再捡起来就有点费劲了,可能也是因为离职变动与薪资维权的原因吧,导致现在已经无法沉下心去学习一些稍微难点的东西,那这篇就聊一些简单的概念东西。
虚拟DOM
这个问题在面试中也经常会问到,如果是vue相关的技术面试,问完虚拟DOM后会应该会追问vue2与vue3的diff算法有什么不同
虚拟dom的概念
虚拟dom本质上就是个js对象,用来表述真实dom的结构,然后通过渲染器,将页面结构生成出来
html
<!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>
<body>
<div>我是一个div,里面只有内容</div>
<script>
const dom={
type:'div',
children:'我是一个div,里面只有内容'
}
</script>
</body>
</html>
vue2 与 vue3 的diff算法
-
vue2 是通过对旧节点列表建立一个 { key, oldVnode } 的映射表,然后遍历新节点列表的剩余节点,根据newVnode.key在旧映射表中寻找可复用的节点,然后打补丁并且移动到正确的位置。
-
vue3 则是建立一个存储新节点数组中的剩余节点在旧节点数组上的索引的映射关系数组,建立完成这个数组后也即找到了可复用的节点,然后通过这个数组计算得到最长递增子序列,这个序列中的节点保持不动,然后将新节点数组中的剩余节点移动到正确的位置
用虚拟 dom 结构来生成页面
创建更新逻辑也比较简单,如果没有老节点,则直接创建挂载,如果有老节点,则暴力清除节点,再重新生成,进行挂载。
html
<!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>
<body>
<div id="app"></div>
<script>
const Vnode1={
type:'div',
children:'我是一个div,里面只有初始化内容'
}
const Vnode2={
type:'h1',
children:'我是一个h1,存放更新的内容'
}
const app=document.querySelector('#app');
const render=(oldVnode,newVnode,container)=>{
if(oldVnode){//有老节点,说明是进行更新操作,则清除根节点,再进行生成
unmount(container)
}
mount(newVnode,container)
}
// 创建节点
const mount=(newVnode,container)=>{
const vnode=document.createElement(newVnode.type)
vnode.innerHTML=newVnode.children
container.appendChild(vnode)
}
const unmount=(container)=>{
container.innerHTML=''
}
render(null,Vnode1,app)
setTimeout(()=>{
render(Vnode1,Vnode2,app)
},5000)
</script>
</body>
</html>
在vue3 中使用虚拟dom生成页面
通过h
函数生成 虚拟 dom
节点,通过 render
函数进行页面挂载渲染。可以和我们上面的流程对比一下
html
<!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>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
</head>
<body>
<div id="app"></div>
<script>
const {render,h}=Vue
const vnode=h('div',{class:'container',onclick:()=>{alert('触发点击事件')}},'我是vnode')
console.log(vnode)
//常用到以下三个属性,第四个属性为标记,在props 中可以定义我们需要的任何属性
// {
// children: "我是vnode",
// props: {class: 'container'},
// type: "div",
// __v_isVNode: true
// }
render(vnode,document.querySelector('#app'))
</script>
</body>
</html>
最后
本篇文章比较简单,vue中虚拟dom的生成流程,对我们对整个框架或者我们自己来封装函数还是有帮助的!