zoukankan      html  css  js  c++  java
  • 虚拟dom详解

    什么是vdom

    顾名思义虚拟dom并非真实的dom,而是由按照一定的规则构成的可对真实dom进行描述的 JS对象。
    结构如下

    //虚拟dom
    {
          tag:'ul',
          attrs :{id:'list'},
          children:[{tag:'li',attrs:{className:'li'},children:['item1']},{tag:'li',attrs:{className:'li'},children:['item2']},{tag:'li',attrs:{className:'li'},children:['item3']}]
    }
    //真实dom
    <ul id="list">
         <li class="li">item1</li>
         <li class="li">item1</li>
         <li class="li">item1</li>
    </ul>
    

    为什么要使用虚拟dom

    1.dom操作是昂贵的,并且会引发浏览器的回流和重绘耗费性能
    2.将 DOM 对比操作放在 JS层,提高效率
    3.浏览器只渲染相应的需要改变的dom,减小回流,重绘成本

    如何使用虚拟dom

    使用:可用 snabbdom 的用法来举例
    h函数 - 用于生成虚拟dom
    patch函数
    patch('container',vdom) 将虚拟dom渲染到 界面上 (createElement)
    patch (vdom,newVdom) 对比新旧虚拟dom,找出差异,并将差异部分在界面上进行改变 ( updateChildren)

    如何理解diff算法

    1 是 linux 的基础命令
    2 vdom 中应用 diff 算法是为了找出需要更新的节点
    3 实现,patch(container, vnode) 和 patch(vnode, newVnode)
    4 核心逻辑,createElement 和 updateChildren

    createElement.js

    function createElement(vnode) {
        var tag = vnode.tag  // 'ul'
        var attrs = vnode.attrs || {}
        var children = vnode.children || []
        if (!tag) {
            return null
        }
    
        // 创建真实的 DOM 元素
        var elem = document.createElement(tag)
        // 属性
        var attrName
        for (attrName in attrs) {
            if (attrs.hasOwnProperty(attrName)) {
                // 给 elem 添加属性
                elem.setAttribute(attrName, attrs[attrName])
            }
        }
        // 子元素
        children.forEach(function (childVnode) {
            // 给 elem 添加子元素
            elem.appendChild(createElement(childVnode))  // 递归
        })
    
        // 返回真实的 DOM 元素
        return elem
    }
    

    updateChildren.js

    function updateChildren(vnode, newVnode) {
        var children = vnode.children || []
        var newChildren = newVnode.children || []
    
        children.forEach(function (childVnode, index) {
            var newChildVnode = newChildren[index]
            if (childVnode.tag === newChildVnode.tag) {
                // 深层次对比,递归
                updateChildren(childVnode, newChildVnode)
            } else {
                // 替换
                replaceNode(childVnode, newChildVnode)
            }
        })
    }
    
    function replaceNode(vnode, newVnode) {
        var elem = vnode.elem  // 真实的 DOM 节点
        var newElem = createElement(newVnode)
    
        // 替换
    }
    
  • 相关阅读:
    洛谷 P2678 跳石头
    洛谷 P1145 约瑟夫
    LibreOJ #515. 「LibreOJ β Round #2」贪心只能过样例
    洛谷 P2966 [USACO09DEC]牛收费路径Cow Toll Paths
    网络编程 --- TCP
    进程
    并发编程
    网络编程 --- UDP
    网络编程
    面向对象编程 --- 反射
  • 原文地址:https://www.cnblogs.com/honkerzh/p/13816138.html
Copyright © 2011-2022 走看看