【总结】vue如何实现的数据控制视图

前言

这篇主要讲的就是vue很重要的一块知识点,双向数据绑定是如何实现的。一开始看这一块的内容的时候比较迷茫,迷茫在如下几个点:html

  • 这块内容该从哪边入手
  • 数据变化是如何驱动视图层更新的
  • 作题深化知识点

从哪边着手去看响应式原理

我这边提供三个方向,从这三个方向,你均可以看到watcher的使用,而后watcher的使用过程当中,会掺杂到observer以及dep,而后以点带面,对总体进行梳理vue

  • 初始化的render流程去看

在lifecycle这个文件中的mountComponent这个方法里,建立了一个watcher。代码以下:bash

new Watcher(vm, updateComponent, noop, {
    before () {
      if (vm._isMounted && !vm._isDestroyed) {
        callHook(vm, 'beforeUpdate')
      }
    }
}, true /* isRenderWatcher */)
复制代码

能够透过这个传参,梳理出整一个app

  • 从watch的角度去看oop

  • 从computed的角度去看post

数据变化是如何驱动视图层更新的

这个问题其实能够分两个方面去看:ui

  • 如何知道数据变化了
  • 如何知道某一块视图和数据有关,并更新他

如何知道数据变化了

答案:数据劫持 this

  • 数据劫持的两种方式
    • Object.defineProperty
    • ES6中的proxy

Vue3.0中的数据劫持是用proxy来实现的,目前阅读的源码中,都是以Object.defineProperty这种方式来实现的。spa

如何知道某一块视图和数据有关,并更新他

答案:依赖收集以及订阅更新 3d

详细解读过程:用图告诉你响应式原理

这里仅用一个简单的例子和图,来明确一下整个流程

<div id="app">
    {{ message }}
    {{ message1 }}
    <input type="text" v-model="message">
    <div @click="changeMessage">改变message</div>        
</div>
复制代码
var app = new Vue({
    el: '#app',
    data: {
        message: '1',
        message1: '2',
    },
    methods: {
        changeMessage() {
            this.message = '2'
        }
    },
    watch: {
        message: function(val) {
            this.message1 = val
        }
    }
})
复制代码
  • 依赖收集流程图

  • 依赖收集的最终结果:

  • 订阅更新流程图:

作题深化知识点

题目以下:

一、简述Vue的响应式原理

二、计算属性和watch的区别

三、Vue中给data中的对象属性添加一个新的属性时会发生什么,如何解决?

对于第一和第二在这里就不花篇幅去说明。

Vue中给data中的对象属性添加一个新的属性时会发生什么,如何解决?

咱们在作业务的时候常常会遇到这样的状况,我举一个简单的例子:

<template>
  <div>
    <ul>
      <li v-for="value in obj" :key="value">
        {{value}}
      </li>
    </ul>
    <button @click="addObjB">添加obj.b</button>
  </div>
</template>
<script>
export default {
  data () {
    return {
      obj: {
        a: 'obj.a'
      }
    }
  },
  methods: {
    addObjB () {
      this.obj.b = 'obj.b'
      console.log(this.obj)
    }
  }
}
</script>
<style></style>
复制代码

依赖收集流程:

从中咱们能够发现,renderWatch是有收集Dep(obj)Dep(Obj.a)的,可是当咱们改变Obj的时候,并无触发视图的更新。由于咱们在改变obj的值的时候,并无去触发Dep(obj)。

产生问题的本质缘由:

一、vue会在state.js文件的initData的方法中,将data属性中的每个key都变成响应式属性。

二、视图在渲染过程当中,会将renderWatcher收集到用到的值的dep中,方便依赖更新(不懂的在回过去看一下依赖收集流程)

三、当你额外添加一个属性的时候,该属性并非响应式属性。

那如何去改变:

addObjB () {
  // this.obj.b = 'obj.b'
  this.$set(this.obj, 'b', 'obj.b')
  console.log(this.obj)
}
复制代码

总结

这篇文章是年度总结的开篇,后续会继续总结初始化部分、render部分和patch部分。

相关文章
相关标签/搜索