Vue学习笔记-vue2数据响应式

133 阅读4分钟

✊不积跬步,无以至千里;不积小流,无以成江海

定义

Vue 中的数据响应式是指,组件的数据一旦发生变化,视图也会相应地更新。

Vue 的数据响应式是通过代理机制实现的。当组件实例化时,Vue 会将组件的数据转换为一个代理对象。代理对象会拦截对数据的访问和修改,并通知 Vue 更新视图。

为什么要转换为代理对象?

代理的作用在小项目中不明显,在大项目中,

定义new.vue的实例为vm,需要修改data中的user name,每次都需要定义vm_datausername来修改变量,就算把vm改成this避免出错每次也要写this.data.username = 'xxx'.

这种写法也太容易出错了,一个命名不慎就需要不停翻找。

vue数据代理此时就将所有的vm下面都生成一个代理,这样直接改写为this.username = 'xxx'即可。只要找准了对应的修改方法,就不会出错。

object.defineProperty()来为数据定义属性

在 Vue 中,object.defineProperty() 方法用于为对象定义属性。它可以设置属性的值、类型、可写性、可配置性等。

object.defineProperty() 方法的语法如下:

object.defineProperty(object, property, descriptor);

其中:

  • object 是对象。
  • property 是属性名。
  • descriptor 是属性描述符。

object.defineProperty() 方法在 Vue 中主要用于实现数据响应式。当使用 reactive() 函数将对象转换为响应式对象时,Vue 会使用 object.defineProperty() 方法为对象的每个属性添加 getter 和 setter。下面介绍这两个方法。

getter 和 setter

getter 用于获取数据属性的值,setter 用于设置数据属性的值。

data() {
  return {
    name: {
      get 名字() {
        return this._name;
      },
      set 名字(value) {
        this._name = value;
      }
    }
  };
}

在vue中其实不存在一个名字叫 ‘名字’的变量,而是通过get 名字 + set 名字 的操作来模拟 名字 这个变量的存在。

数据属性与数据响应式的结合举例

例如,以下代码将对象 obj 转换为响应式对象:

const obj = reactive({ name: 'Vue' });

在内部,Vue 会使用以下代码为对象 objname 属性添加 getter 和 setter:

Object.defineProperty(obj, 'name', {
  get() {
    return this._name;
  },
  set(value) {
    this._name = value;
    // 通知 Vue 更新视图
    this.$forceUpdate();
  }
});

这样,当 obj.name 属性的值发生变化时,Vue 会收到通知并更新视图。

综上所述,总结一下这个小节,vue通过get/set实现对属性的读写监控,以便于能够及时的更新render-UI-视图。这也是vue的双向绑定。

总结

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

当我在data里面传一个对象之后,这个对象就是我们的内部数据。new vue就能够对这个内部数据进行监听和改造。于是n:0就变成了let value = 0,同时vue会通过 get n() {return value;}, set n(v) {value = v;} 这种方式生成一个被修改的对象。之后我再对这个被修改过的原始的对象进行代理。具体如图

截屏2024-01-05 20.24.55.png

cue一下闭包

只要一个函数用到它外部的变量就是闭包。所以value闭包了。get中return的value其实是外部变量。

响应式网页

改变网页的大小,网页内容也会随之变化。具体例子可以自己翻一下优秀案例!~

如何set一个新的未定义的值

在new vue的data中,我可能会声明一部分的变量,但是存在一种情况,在method中用的时候调用了一些未定义的变量。为了尽量解决这种情况,可以用vue.setthis.$set

在 Vue 中,vue.set() 方法用于在响应式对象中设置属性。它可以确保属性的值被 Vue 追踪到,并在属性值发生变化时更新视图。

vue.set() 方法的语法如下:

vue.set(object, property, value);

其中:

  • object 是响应式对象。
  • property 是属性名。
  • value 是属性值。

vue.set() 方法可以用于以下场景:

  • 在响应式对象中设置属性的值。
  • 向响应式对象中添加新属性,修改响应式对象中属性的值。
  • 触发UI更新。

需要注意的是,vue.set() 方法只能用于响应式对象。如果对象不是响应式的,vue.set() 方法将不会触发 Vue 的响应式机制,视图也不会更新。

以下是一些关于 vue.set() 方法的注意事项:

  • vue.set() 方法不会检查属性是否存在。如果属性不存在,Vue 将会为其创建一个新的属性。
  • vue.set() 方法不会检查属性是否可写。如果属性不可写,Vue 将会抛出异常。
  • vue.set() 方法是一个同步方法。它会在设置属性值之前等待所有对该属性的读取操作完成。

数据响应式的变异:数组

数据在列举时是很难去定义长度的,因为有些数据很难被挂去定义有多长(比如新建用户的id)。

在data中,array: ["a", "b", "c"]实际上是array: [0:"a", 1:"b", 2:"c"]

那么当你添加一个新的d的时候,相当于告诉数组我这时候要添加一个3:d,但是由于上面的set相关知识可以知道,对于未定义的 “3:d”,数组根本不认为这是应该被修改的数据,因此并不能成功添加。

当然利用set语法可以添加成功,但是是否所有的数组操作全部都要用set呢?

其实尝试push操作的话也可以发现是能够push成功的。这时候疑问就来了,当你去看生成数组的原型时,你会发现push操作的原型变成了mutator,并不是之前数组push操作的常见原型。

那么vue做了什么呢?对于vue中的push,其实它进行了两步操作。1.使用数组的push 2.建立代理对象mutator并进行监听。其中mutator有七个方法,分别对应为:1. push() 2.  pop() 3.  shift() 4.  unshift() 5.  splice() 6.  sort() 7.  reverse()。