1. 虚拟DOM
JS引擎执行JS代码是很快的,比直接操作真实DOM要快的多。数据改变 --> 虚拟DOM(计算变更)—> 操作真实DOM —> 视图更新
在jquery时代,数据改变 —> 操作真实DOM —> 视图更新,是直接操作真实的DOM。vue框架引入了虚拟DOM
什么是虚拟DOM?
- 虚拟DOM就是使用JS对象模拟真实的DOM结构,用JavaScript对象描述DOM的层次结构。DOM中的一切属性都在虚拟DOM中有对应的属性。
- vue当中虚拟DOM的实现是参考一个库,snabbdom
为什么要有虚拟DOM
-
diff算法是发生在虚拟DOM上的,新虚拟DOM和老虚拟DOM进行diff(精细化比较),算出应该如何最小量更新,最后反映到真正的DOM上。
-
从真实DOM变成虚拟DOM属于模板编译的内容。diff算法研究最小量更新,并将虚拟DOM变成真实的DOM
snabbdom库
- snabbdom是著名的虚拟DOM库,是diff算法的鼻祖,Vue源码借鉴了 snabbdom
- 在git上的snabbdom源码是用Typescript写的,git上并不提供编译好的Javascript版本。如果要直接使用build出来的JavaScript版的snabbdom库,可以从npm上下载:
npm i snabbdom
- snabbdom库是DOM库,不能在nodejs环境运行
h函数
h函数用来产生虚拟节点(vnode),由vnode组成的树就是虚拟DOM树
Vnode的优点
- 兼容性强,不受执行环境的影响。
VNode
因为是JS
对象,不管Node
还是浏览器,都可以统一操作,从而获得了服务端渲染、原生渲染、手写渲染函数等能力。 - 减少操作
DOM
,任何页面的变化,都只使用VNode
进行操作对比,只需要在最后一步挂载更新DOM
,不需要频繁操作DOM
,从而提高页面性能。
虚拟节点有哪些属性
children
: 值可能是undefined(是undefined表示没有子元素),也可能使数组data
: {}elm
: undefined。elm是undefined说明这个节点还没有在DOM树上key
: undefinedsel
: “div”。选择器text
:文字描述
h函数可以产生虚拟节点,h函数可以嵌套使用,从而得到虚拟DOM树。第二个参数可以省略。第三个参数可以是文字、数组、或者h函数
patch函数,让虚拟结点上树
import {
init,
classModule,
propsModule,
styleModule,
eventListenersModule,
h,
} from "snabbdom";
// 创建patch函数
let patch = init([classModule, propsModule, styleModule, eventListenersModule]);
// 创建一个虚拟节点,但是它还没有在DOM树上。要想把它放在DOM树上,需要patch函数
let vnode1 = h('a', {
props: {
href: 'http://www.baidu.com',target:'_blank'}}, '百度一下')
let container = document.getElementById('container');
// 让虚拟结点上树,patch函数只能让一个虚拟结点上树。如果vnode2和vnode3要上树,需要把这个注释掉
patch(container, vnode1);
let vnode2 = h('div',{
class:{
"box":true}},'我是一个盒子');
let vnode3 = h('ul',{
},[
h('li','苹果'), // 第二个参数可以没有
h('li','香蕉'), // 这里已经调用了h函数
h('li',[
h('p',{
},'桔子'),
h('p',{
},'哈哈')
]),
h('li','西瓜'),
h('li',h('span','火龙果')) // 如果children只有一个子元素,第三个参数可以不要数组
]);
手写h函数
h函数有很多种用法,第二个和第三个参数都可以省略。h函数源码中对参数是否存在做了很多的判断,在这里 我们只实现有三个参数的h函数。
// vnode.js
export default function vnode(sel, data, children, text, elm) {
return {
sel, data, children, text, elm};
}