Vue中diff算法详解

Posted AI_huihui

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Vue中diff算法详解相关的知识,希望对你有一定的参考价值。

 首先带大家了解一下虚拟DOM概念 

一、虚拟DOM本质

        虚拟DOM本质就是一个js对象,用来保存DOM关键信息 。

二、虚拟DOM概念

        后缀名为 .vue文件中的 template 里写的标签,都是模板,都会被vue处理成虚拟DOM对象来渲染显示在浏览器(真实dom页面)上。

  1. 内存中生成一样的虚拟DOM结构
            项目中的DOM属性有很多个,我们无法很快知道什么属性改变,比如在template中的标签结构为:
     
    <template>
        <div id='app'>
            <p class='app_p'>虚拟DOM</p>
        </div>
    </template>
    相当于
     
    const virtualDom = {
            type:'div',
            attributes:[{id:'app'}],
            children:{
                type:'p',
                attributes:[{class:'app_p'}],
                text:'虚拟DOM'
            }
    }
  2. 当进行vue的数据更新

    生成新的虚拟DOM结构

    和旧的虚拟DOM结构进行比较

    利用diff算法,找出不同,然后更新变化的部分重绘到页面,也叫做打补丁。
  3. 重绘和回流的概念
     

    回流(重排): 当浏览器必须重新处理和绘制部分或全部页面时,回流就会发生。

    重绘: 不影响布局, 只是标签页面发生变化, 重新绘制。

    注意: 回流(重排)必引发重绘, 重绘不一定引发回流(重排)。


 一、什么是diff算法

        diff算法是一个Virtual DOM的加速器,其算法的改进优化是React整个界面渲染的基础和性能的保障,同时也是React源码中最神秘的,最不可思议的部分。vue中,diff算法就是让新虚拟dom, 和旧的虚拟dom相比较。

二、vue中diff算法分析

 vue中用diff就是通过同级比较dom树,来进行重绘或者回流。分为三种情况:

  1. 根元素变了,删除重建整个DOM树

    旧虚拟DOM

    <div id='app'>
        <p class='app_p'>虚拟DOM</p>
    </div>

     新虚拟DOM

    <div id='app' >
        <span class='app_p'>虚拟DOM</span>
    </div>
  2. 根元素没变,属性改变,更新属性,元素复用

     旧虚拟DOM

    <div id='app'>
        <p class='app_p'>虚拟DOM</p>
    </div>

     新虚拟DOM

    <div id='app' title='新虚拟DOM'>
        <p class='app_p'>虚拟DOM</p>
    </div>

  3. 根元素和子元素都没变,但元素里的内容改变

     没有设置key值
          v-for 不会移动DOM,而是复用DOM元素,就地更新

    <ul id="ul">
        <li v-for="item in arr">
            {{ item }} 
            <input type="text">
        </li>
    </ul>
    <button @click="addFn">新增一个</button>
    export default {
        data(){
            return {
                arr: ["小黑", "小黄", "小白"]
            }
        },
        methods: {
            addFn(){
                this.arr.splice(1, 0, '小绿')
            }
        }
    };

     新虚拟DOM会对照旧虚拟DOM来更新,因为只是内容改变,而标签并没有变,所以从第二个标签开始的内容会改变,再增加一个标签更新新的数据对应新的视图。

    设有key值
        因为新旧虚拟DOM对比,key存在就复用此标签更新内容,如果不存在就直接创建一个新的

    <ul id="ul">
        <li v-for="(item, index) in arr" :key="index">
            {{ item }} 
            <input type="text">
        </li>
    </ul>
    <button @click="addFn">新增一个</button>
    export default {
        data(){
            return {
                arr: ["小黑", "小黄", "小白"]
            }
        },
        methods: {
            addFn(){
                this.arr.splice(1, 0, '小绿')
            }
        }
    };
        v-for先循环产生新的DOM结构, key是连续的,和数据对应然后比较新旧DOM结构,找到区别,打补丁到页面上最后补一个li,然后从第二个往后,都要更新内容。
        key值只能是唯一不重复的,字符串或数值,新DOM里数据的key存在, 去旧的虚拟DOM结构里找到key标记的标签,复用标签新DOM里数据的key存在,去旧的虚拟DOM结构里没有找到key标签的标签,创建旧DOM结构的key,在新的DOM结构里没有了,则移除key所在的标签。不加key值不影响功能,添加key值可以提高更新性能。

总结 :

  • 根元素改变 – 删除当前DOM树重新建

  • 根元素未变, 属性改变 – 更新属性

  • 根元素未变, 子元素/内容改变

  • 无key – 就地更新 / 有key – 按key比较

以上是关于Vue中diff算法详解的主要内容,如果未能解决你的问题,请参考以下文章

Vue中diff算法详解

React的diff算法详解

vue的diff算法详解

Snabbdom:虚拟DOM和Diff算法

你怎么理解vue中的diff算法?

React源码揭秘:Diff算法详解