解释Vue深入响应式原理

tip:实例创建之后添加新的属性到实例上,不会触发视图更新

分解tip:new Vue() 生命周期created() 之后 在data内添加的属性,不会触发view层的更新

new Vue({{
  el: '#app',
  data: {
    user: {
      name: 'tom',
      sex: 'male'
    }
  },
  created() {
    this.user.msg = 'reactivity'  // 成功创建并在视图更新
  },
  mounted() {
    this.user.data = 'reactivity' // 成功创建,但不更新视图
  }
})

解决方法

1Vue API

vm.$set(obj, key, value)

2Object.assign()

Object.assign({}, this.user, {key: value})
new Vue({{
  el: '#app',
  data: {
    user: {
      name: 'tom',
      sex: 'male'
    }
  },
  created() {
    this.user.msg = 'reactivity'  // 成功创建并在视图更新
  },
  mounted() {
    this.$set(this.user, 'data', 'reactivity') // Vue API
    Object.assign({}, this.user, {'data', 'reactivity'}) // Object.assign
  }
})

异步数据操作

异步获取数据后更新视图:

new Vue({{
  el: '#app',
  data: {
    user: {
      name: 'tom',
      sex: 'male'
    }
  },
  created() {
     setTimeout(() => {
      // this.user.msg = 'reactivity'  // 不更新视图
      this.$set(this.user, 'data', 'reactivity') // Vue API
      Object.assign({}, this.user, {'data', 'reactivity'}) // Object.assign
    }, 1000) // 模拟异步数据
  },
  mounted() {
  }
})

原理:异步数据操作的栈队列在整个vue生命周期最后

异步更新队列

this.$nextTick() 下一次栈队列执行完毕之后
异步数据更新后,操作对应的dom更新

new Vue({{
  el: '#app',
  data: {
    user: {
      name: 'tom',
      sex: 'male'
    }
  },
  created() {
     setTimeout(() => {
       this.user = {'age': 18}
       this.$nextTick(() => {
        // 数据刷新后对应的dom更新完毕
      })
    }, 1000) // 模拟异步数据
  },
  mounted() {
  }
})

MutationObserver

vue2.0使用MutationObserver API作为异步更新队列的DOM更新解决方案
MutationObserver属于microtasks,执行效率更高,优先于macrotasks - setTimeout执行

    // Firefox和Chrome早期版本中带有前缀
    const MutationObserver = window.MutationObserver
    || window.WebKitMutationObserver || window.MozMutationObserver
    // 创建观察者对象
    const observer = new MutationObserver(mutations=>{
      mutations.forEach(function(mutation) {
        console.log(mutation.type);
      })   
    }) 
    // 配置观察选项:
    const config = { 
      attributes: true, 
      childList: true, 
      characterData: true 
    }
    // 选择目标节点
    const target = document.querySelector('#test');
    // 传入目标节点和观察选项
    observer.observe(target, config);

    target.appendChild(document.createElement("div"))   
    /*
    * mutationObserver优先于setTimeout
    */
    setTimeout(console.log,0,'setTimeout')
    console.log('appending')  
    target.setAttribute('class','hello')                       //添加了一个元素子节点,触发回调函数.

    // 随后,你还可以停止观察
    // observer.disconnect();


    /*
    * doc  https://developer.mozilla.org/zh-CN/docs/Web/API/MutationObserver
    */
执行结果
/*
appending
childList
attributes
setTimeout
*/

MutationObserver

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容