• vue的虚拟dom(Virtual DOM )


    模板转换成视图的过程

    在底层实现中Vue会将模板编译成渲染函数,当然我们也可以不写模板,直接写渲染函数,以获得更好的控制。

    渲染函数:渲染函数是用来生成Virtual DOM的;
    VNode虚拟节点:vnode可以理解成dom节点的描述对象,它描述了应该怎样去创建真实的DOM节点;
    patch(patching算法):虚拟DOM最核心的部分,它可以将vnode渲染成真实的DOM。这个过程是对比新旧虚拟节点之间有哪些不同,然后根据对比结果找出需要更新的的节点进行更新。其实际作用是在现有DOM上进行修改来实现更新视图的目的;

    Virtual DOM

    Virtual DOM用JS对象来描述dom的节点(VNode),这个对象至少包含标签名( tag)、属性(attrs)和子元素对象( children)这三个属性。它是对真实 DOM 的抽象,最终可以通过一系列操作把这个对象转化为真实的dom。

    具体步骤为

    Virtual DOM 本质上就是在 JS 和 DOM 之间做了一个缓存

    Virtual DOM的作用

    虚拟DOM的最终目标是将虚拟节点渲染到视图上,但是如果直接使用虚拟节点覆盖旧节点的话,会有很多不必要的DOM操作。例如,一个ul标签下很多个li标签,其中只有一个li有变化,这种情况下如果使用新的ul去替代旧的ul,因为这些不必要的DOM操作而造成了性能上的浪费。
    为了避免不必要的DOM操作,虚拟DOM在虚拟节点映射到视图的过程中,将虚拟节点与上一次渲染视图所使用的旧虚拟节点(oldVnode)做对比,找出真正需要更新的节点来进行DOM操作,从而避免操作其他无需改动的DOM。
    其实虚拟DOM在Vue.js主要做了两件事:
    提供与真实DOM节点所对应的虚拟节点vnode;
    将虚拟节点vnode和旧虚拟节点oldVnode进行对比,然后更新视图;

    Virtual DOM的diff算法

    递归地进行同级vnode的diff,最终实现整个DOM树的更新

     步骤:

    用 JavaScript 对象结构表示 DOM 树的结构;然后用这个树构建一个真正的 DOM 树,插到文档当中;
    当状态变更的时候,重新构造一棵新的对象树。然后用新的树和旧的树进行比较,记录两棵树差异;
    把所记录的差异应用到所构建的真正的DOM树上,视图就更新了;

    Virtual DOM的优点

    跨平台的优势:由于 Virtual DOM 是以 JavaScript 对象为基础而不依赖真实平台环境,所以使它具有了跨平台的能力,比如说浏览器平台、Weex、Node 等;

    提高效率:操作 DOM 慢,js运行效率高,所以将DOM对比操作放在JS层可以提高效率;

    提高渲染性能:通过patch 的核心----diff 算法,找出本次DOM需要更新的节点来更新,其他的不更新。比如修改某个model 100次,从1加到100,那么有了Virtual DOM的缓存之后,只会把最后一次修改patch到view上。

    nextTick

    this.$nextTick(()=> {
      // 操作。。。
    })

    1 Vue生命周期的created()钩子函数进行的DOM操作一定要放在Vue.nextTick()的回调函数中;

    2 当项目中你想在改变DOM元素的数据后基于新的dom做点什么,对新DOM一系列的js操作都需要放进Vue.nextTick()的回调函数中;

    3 在使用某个第三方插件时 ,希望在vue生成的某些dom动态发生变化时重新应用该插件,也会用到该方法;

    改变数据有时不更新

    1 vue实现数据双向绑定有这么一个过程:当你把一个普通的 JavaScript 对象传给 Vue 实例的 data 选项,Vue 将遍历此对象所有的属性,并使用Object.defineProperty() 把这些属性全部转为getter/setter。每个组件实例都有相应的 watcher 实例对象,它会在组件渲染的过程中把属性记录为依赖,之后当依赖项的 setter 被调用时,会通知 watcher 重新计算,从而致使它关联的组件得以更新。实现数据data变化更新视图view。

    var vm = new Vue({
        data:{
            a:1;   // vm.a 是响应的
        }
    })
    vm.b = 2;   // vm.b 是非响应的

    2 没有更新dom是因为改变数据之后Object.defineproperty()的set方法没有被触发,即没有监测到数据更新。以下几种情况会出现这个问题:

      当你利用索引直接设置数组的一项时,例如:this.items[indexOfItem] = newValue;

      当你修改数组的长度时,例如:this.items.length = newLength;

           数组的push,splice等方法也不会更新dom; 

      对象里边的修改:

    data () {
        return {
            student: {
                name: ''
            },
            teach:["李磊"]
         }
    }
    
    // 以下操作不会触发视图更新
    this.student.name="XXX";

    解决办法:

    1 使用set:

    this.$set('对象名', key, value);   // 对象写法
    this.$set(this.teach,0, “韩梅梅”);   // 数组写法

    2 使用deep

    watch:{
        student:{
           handler:(n,o)=>{
               //逻辑处理
           },
           deep:true
        }    
    }

    3  改变原对象或数组的地址

    this.obj = Object.assign({},this.obj,{"sex","man"});

    原文:https://www.cnblogs.com/fundebug/p/vue-virtual-dom.html

  • 相关阅读:
    [置顶] 深入理解android之IPC机制与Binder框架
    cdn加速对门户网站产生的影响
    极客技术专题【007期】:jQuery初学者入门
    linux 下信号处理命令trap && linux下各种信号的意义
    利用ACE 自己实现的线程池
    漫谈开发前奏之编译器
    jar,war,ear区别及java基础杂七八
    java出现no XXX in java.library.path的解决办法及eclipse配置
    Windows下GNU之gcc体验方法
    防asp木马运行
  • 原文地址:https://www.cnblogs.com/xjy20170907/p/12684706.html
Copyright © 2020-2023  润新知