如果一个物体能对外界的刺激作出反应,它就是响应式的。

Vue的data是响应式



const vm=new Vue({data:{n:0}})



如果我修改了vm.n,那么UI中的n就会来响应我

要理解Vue数据响应式,我们需要对以下概念有一个了解

  • getter
  • setter
  • Object.defineProperty

getter/setter用于对属性的读写进行监控,Object.defineProperty可以给对象添加属性value,和getter/setter

Vue作者尤雨溪为了不让用户随便篡改data,就会监听data的变化,再用一个新的对象作为代理(一种设计模式)



let myData={n:0}
let data5=proxy({data:myData}) //括号里是匿名对象 无法访问    
function proxy({data}){  //析构赋值
     let value=data.n    //用新的value获取data.n,这样就可以监听data.n的变化   
     Object.defineProperty(data,'n', {  //这里的n是虚拟,不能被修改
         get(){
               return value
             },
           set(newValue) {
                if(newValue <0 ) return 
                     value=newValue
               }
         })

const obj={}   //声明一个新的对象,把data.n全权负责给obj,这样不论怎么篡改,都不会影响
Object.defineProperty (obj,'n' ,{
     get () {
           return data.n
         },
      set(value) {
            if(value<0) return
               data.n=value
         }
 })
return obj  //obj就是代理
}



data里的属性可以有多个,用一个for循环把key找出来,然后一一加代理

Object.defineProperty的问题

Object.definePropety(obj, 'n', { ... } )

必须要有一个'n',才能监听&代理obj.n,如果n没有定义,Vue会给出一个警告。但是Vue只会检查第一层的属性,但是如果代码写成这样,那么Vue就不会给警告



new Vue ( {
   data: {
      obj: {
          a:0
       }
   },
   template: `
  <div>
    {{obj.b}}
  <button @click="setB"> set b </button>
  </div>
`  ,
   methods : {
      setB() {
         this.obj.b=1
       }
    }
}).$mount("#app")



页面上不会显示obj.b,因为它没有定义。但是Vue不会报错,我们成功绕过了Vue第一层的见检查。

一句到底就是,如果要代理&监听对象的key,这个key必须存在

解决方法:①把key都声明好,后面不再加属性②使用Vue.set或者this.$set

Vue.set和this.$set的作用是:

  1. 新增key
  2. 自动创建代理和监听(如果没有创建过)
  3. 出发UI更新(异步更新,这里不细讲)

举例



this.$set(this.obj, 'm' , 100)



但是有些特殊情况没法提前声明所有的key

data中有数组

数组的长度可以一直增加,下标就是key。如果每次都用Vue.set或者this.$set会很麻烦

Vue文档中介绍的,7种Vue新增的编译方法




Vue 监听容器宽高变化_vue 实时监听页面宽度变化


new Vue({
  data: {
    array: ["a", "b", "c"]
  },
  template: `
    <div>
      {{array}}
      <button @click="setD">set d</button>
    </div>
  `,
  methods: {
    setD() {
      // this.array[3] = "d"; //请问,页面中会显示 'd' 吗?
      this.array.push("d");  //能正确显示
      console.log(this.array);
    }
  }
}).$mount("#app");


Array第一层原型里有这七个方法

总结

简而言之,数据响应式就是 Vue 对 data 进行了内部的监听和代理,从而使数据不被其他手段改变,在正确方法中实现的 data 改变并实时渲染到页面 UI 中