您的位置:首页 > 其它

virtual dom 虚拟DOM

2020-02-13 21:46 71 查看
  • vdom是vue和React的核心,先讲哪个都绕不开它
  • vdom比较独立,使用也比较简单
  • 如果面试闻到vue和React和实现,免不了问vdom

vdom是什么?为何会存在vdom?

  • virtual dom,虚拟DOM
  • 用JS模拟DOM结构
  • 将DOM对比操作放在JS层来做,提高效率
  • 提高重绘性能

为何会存在:

  • DOM操作是“昂贵”的,js运行效率高
  • 尽量减少DOM操作,而不是“推倒重来”
  • 项目越复杂,影响就越严重
  • vdom即可解决这个问题

vdom如何应用,核心API是什么

使用snabbdom

<body>
<div id="container"></div>
<button id="btn-change">change</button>

<script src="https://cdn.bootcss.com/snabbdom/0.7.1/snabbdom.js"></script>
<script src="https://cdn.bootcss.com/snabbdom/0.7.1/snabbdom-class.js"></script>
<script src="https://cdn.bootcss.com/snabbdom/0.7.1/snabbdom-props.js"></script>
<script src="https://cdn.bootcss.com/snabbdom/0.7.1/snabbdom-style.js"></script>
<script src="https://cdn.bootcss.com/snabbdom/0.7.1/snabbdom-eventlisteners.js"></script>
<script src="https://cdn.bootcss.com/snabbdom/0.7.1/h.js"></script>
<script>
var snabbdom = window.snabbdom

// 定义patch
var patch = snabbdom.init([
snabbdom_class,
snabbdom_props,
snabbdom_style,
snabbdom_eventlisteners
])

// 定义h
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')
])

patch(container, vnode)

document.getElementById('btn-change').addEventListener('click', function(){
var newVnode = h('ul#list', {}, [
h('li.item', {}, 'Item 1'),
h('li.item', {}, 'Item B'),
h('li.item', {}, 'Item 3')
])
patch(vnode, newVnode)
})

</script>
</body>

介绍一下diff算法

  • 什么是diff算法?
  • vdom为何用diff算法?
    (1)DOM操作是“昂贵”的,因此尽量减少DOM操作
    (2)找出本次DOM必须更新的节点来更新,其他的不更新
    (3)这个“找出”的过程,就需要diff算法
  • diff算法实现流程
    (1)patch(container, vnode)
    (2)patch(vnode, newVnode)
// patch(container, vnode)情况
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(attrs.hasOwnProperty(attrName)){
// 给elem添加属性
elem.setAttribute(attrName, attrs[attrName])
}
}

children.forEach(childVnode => {
// 给elem田间子元素
elem.appendChild(createElement(childVnode))  // 递归
})

// 返回真实的DOM元素
return elem
}

// 数据
{
tag: 'ul'
attrs: {id: 'list'},
children: [
{
tag: 'li',
attrs: {className: 'item'},
children: ['Item 1']
}, {
tag: 'li',
attrs: {className: 'item'},
children: ['Item 2']
}
]
}
// patch(vnode, newVnode)情况
function updateChildren(vnode, newVnode){
var children = vnode.children || []
var newChildren = newVnode.children || []

// 遍历现有的children
children.forEach(function(child, index){
var newChild = newXChildren[index]
if(newChild == null){
return
}
if(child.tag === newChild.tag){
// 两者tag一样
updateChildren(child, newChild)
} else {
replaceNode(child, newChild)
}
})
}

核心API:

  • h函数
  • patch函数
  • 点赞
  • 收藏
  • 分享
  • 文章举报
前端小兔子 发布了22 篇原创文章 · 获赞 0 · 访问量 428 私信 关注
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: