virtual dom 虚拟DOM

  • 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函数
发布了23 篇原创文章 · 获赞 0 · 访问量 504

猜你喜欢

转载自blog.csdn.net/qq_33084055/article/details/103925199