## 虚拟dom(virtual dom vdom)
1. vdom是vue和React的核心
2. vdom比较独立,使用也比较简单
### 问题
1. vdom是什么,为什么存在vdom?
2. vdom如何应用,核心api是什么?
3. 介绍一些diff算法
#### 问题详细
* [ ] vdom是什么,为什么存在vdom?
1. 什么是vdom
* virtual dom,虚拟dom
* **用js模拟dom结构**
* **dom变化的对比,放在js层来做**(图灵完备语言(判断,循环,递归,高复杂逻辑)(html,css都不是))
* 提高**重绘性能**
* **dom操作非常昂贵**
* **将dom对比放在js层,提高效率**
js模拟dom
~~~
{
tag:'ul',
attrs:{ id :'list'},
children:[{
{
tag:'li',
attrs:{className:'item'},
children:['Item1']
}
}],
}
~~~
**浏览器最耗费性能的是dom操作,js操作一万遍没关系,dom操作一遍都不行,现在浏览器执行js是非常快的,所有vdom非常有价值**
2. 设计一个需求场景
将数据展示成一个表格,随便修改一个信息,表格跟着变化
3. 用jQuery来实现
~~~
//jquery比较高效的实现
function render(data){
var $container = $('#container');
$container.html('');
//拼接table
var $table = $("<table>")
$table.append($("<tr><td>..."));
data.forEach(function(item){
$table.append($('<tr><td>'+item.name+...))
})
//渲染到页面(执行一次渲染,属于比较高效的)
$container.append($table);
}
~~~
dom操作是最昂贵的
~~~
var div = document.createElement('div');
var item ,result = '';
for(item in div){
result +="|" +item;
}
console.log(result)
~~~
能看到**dom节点属性数量非常非常多**,是一个**非常复杂的属性节点**,侧面反映出dom的复杂性。js的模拟会更加简单一些,**应尽量少的做dom操作,尽量用js来代替**。
4. 遇到的问题
* **dom操作是“昂贵的”,js运行效率高**(js都能用到后端做server语言执行)
* **尽量减少dom操作,不是“推倒重来”**
* **项目越复杂,影响越严重**
* vdom可解决这个问题
* [ ] vdom如何应用,核心api是什么
1. 介绍**snabbdom** (开源vdom的库),vdom是一类技术实现,能实现vdom的库很多
~~~
var container = document.getElementById("container");
var vnode = h('div#container.two.classes',
{on:{click:someFn}},
[h('span',{style:{fontWeight:'bold'}},'this is bold'),
'and this is just noraml text',
h('a',{props:{href:'/foo'}},'I talk you place')
}
);
//第一个参数是真实的dom节点
patch(container,vnode);
var newVnode = h('div#container.two.classes',
{on:{click:anotherEventHandler}},
[h('span',{style:{fontWeight:'normal',fontStyle:'italic'}},'this is now italic type'),
'and this is still just noraml text',
h('a',{props:{href:'/bar'}},'I talk you place')
}
);
patch(vnode,newVnode);
~~~
**h()函数生成vnode节点,模拟真实的dom节点(vnode)**
vnode:js模拟的node(dom节点),单个的节点
vdom:js模拟的dom
**patch(container,vnode)**://第一个参数是真实的dom节点
**在第一次渲染时,将全部的数据源全部渲染出来**(把vnode表述的dom节点全部塞给container)
**patch(vnode,newVnode);**//第二次渲染 新的vnode和旧的vnode进行对比
进行**复杂的对比**,**只找出需要更新的部分进行更新**
2. 重做之前的demo
3. 核心api h()函数和patch()函数
~~~
snabbdom.js snabbdom-class.js snabbdom-props.js snabbdom-style.js snabbdom-eventlisteners.js snabbdom-h.js
vdom技术实现是很复杂的
var snabbdom = window.snabbdom;//全局对象
//定义patch
var patch = snabbdom.int([
snabbdom_classs,
snabbdom_props,
snabbdom_style,
snabbdom_eventlisteners,
]);
var h = snabbdom.h;
var container = document.getElementById("container")
//生成vnode
var vnode = h("ul#list",{},[
h('li.item',{},"Item 1"),
h('li.item',{},"Item 2"),
])
//执行pactch
patch(container,vnode);
document.getElementById("btn-chang").addEventListener('click',function(){
var newVnode = h("ul#list",{},[
h('li.item',{},"Item 1"),
h('li.item',{},"Item b"),
h('li.item',{},"Item 3"),
]);
//执行pactch 找出差异,根据差异渲染
patch(vnode,newVnode);
});
~~~
~~~
var data = [{},{}];
data.unshifit({name:'',age:'',address})
var contariner = document.getElementById("container")
var vnode;
function render(data){
var newVnode = h(‘table’,{},
data.map(function(item){
var tds = [];
var i;
for(i in item){
if(item.hasOwnProperty(i)){
tds.push(h('td',{},item[i]+''));
}
}
return h('tr',{},tds);
});
//存储当前vnode结果
vnode = newVnode;
);
if(vnode){
//比较渲染
patch(vnode,newVnode);
}else{
//初次渲染
patch(container,vnode);
}
}
render(data);
document.getElementById("btn-chang").addEventListener('click',function(){
data[1].age=10;
data[2].address="bjing"
//re-render
//执行pactch 找出差异,根据差异渲染
render(data)
});
~~~
### 核心api
1. h()函数
* h('<标签名>',{...属性},[...子元素..])
* h('<标签名>',{...属性},'...')
2. patch()函数
* patch(container,vnode);
* patch(vnode,newVnode);
### 问题解答
如何使用?应用snabbdom的用法来举例
* 核心api:h函数 patch函数:初次渲染,再次渲染
*****
### 介绍一下diff算法
1. 什么是diff算法
linux命令 diff:文本文件的异同
git diff判断两个版本文件的差异
git add之前,git status 再看一下文件差异 git diff
diff算法不是vue和react提出的,很早之前就存在的,以前就用来对比文件字符串等
**diff:对比两个虚拟dom节点**
2. 去繁就简
diff算法非常复杂,实现难度大,源码来很大
去繁就简,讲明白核心流程,不关系细节
面试官也不清楚细节
去繁就简后依然难度很大
3. vdom为何用diff算法
* **dom操作是非常消耗性能的,因此尽量减少dom的操作**
* **找出本次dom必须更新的节点来更新,其他的不更新**
* **这个“找出”的过程,就需要diff算法**
真正用处:**找出前后两个vnode(虚拟dom节点)之间的真正差异,然后更新差异,其他的不更新**
4. diff算法实现流程
* patch(container,vnode);
vnode怎么生成真正的dom元素?
~~~
function createElement(vnode){
var tag = vnode.tag;
var attrs = vnode.attrs;
var children = vnode.children||[];
if(!tag){ return null};
var elem = document.createElement(tag);
var attrName
for(attrName in attrs){
if(attr.hasOwnProperty(attrName)){
elem.setAttribute(attrName,attrs[attrName]);
}
}
children.forEach(function(childnode){
//递归 给elem添加子元素
elem.appendChild(createElement(childVnode));
})
//返回真实的dom元素
return elem
}
~~~
* patch(vnode,newVnode);
~~~
function updateChildren(vnode,newVnode){
var children = vnode.children||[];
var newChildren = newVnode.children||[];
children.forEach(function(child,index){
var newChild = newChildren[index];
if(newChild == null){ return; }
if(child.tag === newChild.tag){
//两个tag一样,进行深层对比 递归
updateChildren(child,newChild)
}else{
//dom元素替换
replaceNode(child,newChild)
}
}
function replaceNode(vnode,newVnode){
var elem = vnode.elem;//真实的dom节点
var newElem = createElement(newVnode)//虚拟dom变成真实dom
//替换
}
~~~
#### 不仅仅是以上的内容
1. 节点的**新增和删除**
2. 节点**重新排序**
3. 节点**属性、样式、事件绑定**
4. 如何极致压榨性能(无底洞,代码是为了压榨性能,不是可读性;性能很优,但可读性太差)
### diff实现过程
1. patch(container,vnode)和patch(vnode,newVnode);
2. createElement
3. updateChildren
### 问题解答
1. 什么是diff算法,是linux(git)的基础命令(对比文本文件,字符串),**在vdom中用于对比js对象**(对比节点和节点的不同)
2. vdom中应用diff算法是为了**找出需要更新的节点**
3. diff实现patch(container,vnode)和patch(vnode,newVnode);
4. 核心逻辑,createElement和updateChildren
*****
### 总结
1. vdom是什么?为何会存在vdom
* virtual dom,虚拟dom
* 用js模拟dom结构
* DOM操作非常“昂贵”
* 将DOM对比操作放在js层,提高效率
2. vdom如何应用,核心api是什么
* snabbdom的做法
* 核心api:h函数(生成vnode节点),patch函数(将vnode节点渲染到页面)
3. 介绍一下diff算法
* 是linux(git)的基础命令(对比文本文件,字符串),**在vdom中用于对比js对象**(对比节点和节点的不同),为了**找出需要更新的节点**
* 实现:patch(container,vnode)和patch(vnode,newVnode);
* 核心逻辑,createElement和updateChildren
- 空白目录
- 双樾
- JS基础知识
- JS-WEB-API
- 开发环境
- 运行环境
- ES6
- 原型
- 异步
- 虚拟dom
- mvvm
- 组件化和React
- hybrid
- 其他
- 补充
- 技巧
- 快乐动起来呀
- css
- 掘金小册子
- js基础知识
- ES6知识点
- JS异步
- JS进阶知识
- 思考题
- DevTools Tips
- 浏览器基础知识
- 浏览器缓存机制0
- 浏览器渲染原理
- 安全防范知识点0
- 从V8中看JS性能优化0
- 性能优化琐碎事
- Webpack性能优化0
- 实现小型打包工具0
- React和Vue
- Vue生命周期
- vue基础知识点
- Vue响应式
- vue高级
- React基础
- Vue.js技术解密
- 准备工作
- 数据驱动
- new Vue()
- vue实例挂载
- 组件化
- 深入响应式原理
- 编译
- 扩展
- Vue Router
- Vuex