zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    ZOJ 1002 Fire Net
    Uva 12889 One-Two-Three
    URAL 1881 Long problem statement
    URAL 1880 Psych Up's Eigenvalues
    URAL 1877 Bicycle Codes
    URAL 1876 Centipede's Morning
    URAL 1873. GOV Chronicles
    Uva 839 Not so Mobile
    Uva 679 Dropping Balls
    An ac a day,keep wa away
  • 原文地址:https://www.cnblogs.com/xjy20170907/p/12684706.html
Copyright © 2011-2022 走看看