vue中监听数据变化,vue监测数组变化

  vue中监听数据变化,vue监测数组变化

  这就涉及到Vue的一个重要特征:响应式系统。数据模型只是一个普通的JavaScript对象。当我们修改它时,视图将被更新,而变化检测是响应式系统的核心。

  

目录

  一、对象的变化检测二。关于对象三的问题。阵列3.1的变化检测。背景3.2。实施四。关于阵列的问题

  

一、Object的变化侦测

  让我们模拟一下检测数据变化的逻辑。

  强调我们要做的事情:当数据发生变化时通知外界(外界会自己做一些逻辑处理,比如重新渲染视图)。

  在我们开始编码之前,我们必须回答以下问题:

  1.如何检测物体的变化?

  请使用Object.defineProperty()。读取数据时会触发Getter,修改数据时会触发setter。

  只有当你能察觉到对象的变化时,你才能在数据发生变化时发出通知。

  2.当数据改变时,我们通知谁?

  通知数据的使用位置。并且数据可以在模板或vm中使用。$watch(),而且在不同的地方行为是不一样的。比如模板要在这里渲染,其他逻辑要在那里执行。所以简单抽象一个类。数据变化时通知它,然后它会通知其他地方。

  这个类被命名为Watcher。是中介。

  3.你依靠谁?

  谁通知,取决于谁,取决于观察者。

  4.什么时候通知?

  修改数据时。即setter中的通知。

  5.你什么时候收集依赖关系?

  因为要告知数据使用的地方。你用的时候要读取数据,所以我们可以在你读取的时候收集,也就是在getter里面收集。

  6.在哪里收集的?

  您可以在每个属性中定义一个数组,与该属性相关的所有依赖项都放在该数组中。

  编码如下(可以直接运行):

  //全局变量,用于存储依赖关系

  设globalData=undefined

  //将数据转化为有响应的数据

  函数defineReactive (obj,key,val) {

  //依赖列表

  let dependList=[]

  Object.defineProperty(obj,key,{

  可枚举:真,

  可配置:真,

  get: function () {

  //收集依赖项(观察器)

  global data dependlist . push(global data)

  返回值

  },

  set:函数reactiveSetter (newVal) {

  if(val===newVal){

  返回

  }

  //通知依赖项(观察器)

  dependList.forEach(w={

  w.update(新瓦尔,瓦尔)

  })

  val=newVal

  }

  });

  }

  //依赖性

  类监视器{

  构造函数(数据、键、回调){

  this.data=data

  this.key=key

  this.callback=回调;

  this . val=this . get();

  }

  //这段代码可以将自己添加到依赖项列表中

  get(){

  //将依赖关系保存在globalData中

  globalData=this

  //读取数据时收集依赖项

  设value=this.data[this.key]

  globalData=未定义

  返回值;

  }

  //数据发生变化时接收通知,然后通知外界。

  更新(新值,旧值){

  this.callback(newVal,oldVal)

  }

  }

  /*下面是测试代码*/

  let data={ };

  //将name属性转换为响应。

  defineReactive(数据,年龄, 88 )

  //当数据年龄发生变化时,会通知观察器,然后观察器再通知外界。

  新观察器(数据,年龄,(新值,旧值)={

  console . log(` outside:new val=$ { new val };oldVal=${oldVal} `)

  })

  Data.age -=1 //控制台输出:outside:new val=87;旧值=88

  继续在控制台下执行data.age -=1,输出外部世界:newVal=86旧瓦尔=87 .

  附上数据、defineReactive、dependList、Watcher与外界的关系图。

  首先,通过defineReactive()方法将数据转换为响应(defineReactive (data, age , 88 )。

  当观察器读取数据时(let value=this.data[this.key]),会触发数据的getter,所以观察器被globalData收集。

  当数据被修改时(data.age -=1),会触发setter,通知依赖者列表,通知依赖者给Watcher(w.update(newVal,Val)),最后Watcher通知外界。

  

二、关于 Object 的问题

  想一想:在上面的例子中,delete data.age的继续执行是否会告知外界?

  不会。因为设置器不会被触发。请继续阅读:

  !声明文档类型

  html lang=en

  头

  meta charset=UTF-8

  meta name= viewport content= width=device-width,initial-scale=1.0

  标题文档/标题

  script src= https://cdn . jsdelivr . net/NPM/vue/dist/vue . js /script

  /头

  身体

  div id=应用程序

  部分

  {{ p1.name }}

  {{ p1.age }}

  /部分

  /div

  脚本

  const app=new Vue({

  埃尔: #app ,

  数据:{

  p1: {

  名称: ph ,

  年龄:18岁

  }

  }

  })

  /脚本

  /body

  /html

  运行后,页面会显示ph 18。我们知道当我们更改数据时,视图会被重新渲染,所以我们在控制台上执行delete app.p1.name,发现页面并没有改变。就像上面例子中执行delete data.age一样,不会触发setter,所以不会通知外界。

  为了解决这个问题,Vue提供了两个API(后面会介绍):vm。$set和vm。$删除。

  如果继续执行app。$delete(app.p1, age ),你会发现页面上没有任何信息(name属性已经用delete删除了,只是当时没有重新渲染)。

  注意:如果在这里执行app.p1.sex=man ,使用数据p1的地方不会被通知。这个问题可以通过vm来解决。$set。

  

三、Array 的变化侦测

  

3.1、背景

  如果数据是let data={a:1,b:[11,22]},它被Object.defineProperty转换成响应后,我们修改数据data.a=2,会通知外界,很好理解;同样的,data.b=[11,22,33]也会通知到外界,但是如果data b用另外一种方式修改,像这个data.b.push(33),就不会通知到外界,因为setter没有取。请参见示例:

  函数defineReactive(obj,key,val) {

  Object.defineProperty(obj,key,{

  可枚举:真,

  可配置:真,

  get: function () {

  console.log(`get val=${val} `)

  返回值

  },

  set:函数reactiveSetter (newVal) {

  if(val===newVal){

  返回

  }

  console . log(` set val=$ { new val };oldVal=${val} `)

  val=newVal

  }

  });

  }

  //下面是测试代码{1}

  让数据={}

  defineReactive(数据, a ,[11,22])

  Data.a.push(33) //get val=11,22(不触发setter){ 2 }

  data.a //get val=11,22,33

  data . a=1//set val=1;OldVal=11,22,33(触发器设置器)

  通过push()方法改变数组的值不会触发setter(第{2}行),所以无法通知外界。这里似乎有一个问题:通过Object.definePropery()方法,只能使对象具有响应性,而不能使数组具有响应性。

  实际上,Object.definePropery()可以将数组变成响应。请参见示例:

  //继续上面的示例,并将测试代码(第{1}行)更改为:

  let data=[]

  defineReactive(数据, 0 ,11)

  data[0]=22//set val=22;旧值=11

  Data.push(33) //不会触发{10}

  虽然Object.definePropery()可以把数组变成响应式的,但是通过data.push(33) (line {10})修改数组仍然不会通知到外界。

  所以在Vue中,数据转化为响应有两种方式:对象使用object . define property();该数组使用另一组。

  

3.2、实现

  在es6中,可以使用代理来检测数组的变化。请参见示例:

  让数据=[11,22]

  设p=新代理(数据,{

  set:函数(目标、属性、值、接收者){

  target[prop]=值;

  console.log(属性集: prop =值);

  返回true

  }

  })

  控制台. log(p)

  p.push(33)

  /*

  输出:

  [ 11, 22 ]

  属性集:2=33

  属性集:长度=3

  */

  之前Es6有点麻烦,可以用拦截器。原理是:当我们执行[]。push(),我们将调用数组原型(Array.prototype)中的方法。我们在[]之间添加一个拦截器。push()和Array.prototype. When []。未来调用push(),首先执行拦截器中的push()方法,拦截器中的push()正在调用Array.prototype中的push()方法,请看示例:

  //数组原型

  让arrayPrototype=Array.prototype

  //创建一个拦截器

  let interceptor=object . create(array prototype)

  //将拦截器与原始数组的方法相关联

  ;(“推入、弹出、取消移位、移位、拼接、排序、反转”)。拆分(,)。forEach(方法={

  let origin=array prototype[method];

  Object.defineProperty(侦听器,方法,{

  值:函数(.args){

  console . log(` interceptor:args=$ { args } } `)

  return origin.apply(this,args);

  },

  可枚举:false,

  可写:真,

  可配置:真

  })

  });

  //测试

  设arr1=[a]

  让arr2=[10]

  arr1.push(b )

  //检测数组arr2的变化

  Object.setPrototypeOf(arr2,interceptor) //{20}

  Arr2.push(11) //拦截器:args=11

  Arr2.unshift(22) //拦截器:args=22

  这个例子向拦截器添加了七个可以改变数组内容的方法。如果需要检测哪个数组的变化,将数组的原型指向拦截器(第{20}行)。当我们通过push等七种方法修改数组时,会在拦截器中触发,这样就可以通知外界了。

  到目前为止,我们只完成了检测数组变化的任务。

  更改数据并通知外界。上面的编码实现只针对对象数据,这里需要针对数组数据。

  让我们思考同一个问题:

  1.如何检测数组的变化?

  interseptor

  2.当数据改变时,我们通知谁?

  看守人

  3.你依靠谁?

  看守人

  4.什么时候通知?

  修改数据时。在拦截器中通知。

  5.你什么时候收集依赖关系?

  因为要告知数据使用的地方。如果你使用数据,你必须读取数据。读取数据时收集。这与对象集合依赖项相同。

  {a: [11,22]}比如我们要用数组A,就必须访问对象的属性A。

  6.在哪里收集的?

  对象在每个属性中收集依赖关系,但是这里我们要考虑数组会触发拦截器中的依赖关系,位置可能会被调整。

  就是这样。不会继续了。在下一篇文章中,我会挑出vue中与数据检测相关的源代码,用这篇文章做一个简要的分析。

  

四、关于 Array 的问题

  //需要自己介绍vue.js。后续也尽可能只列出核心代码。

  div id=应用程序

  部分

  {{ p1[0] }}

  {{ p1[1] }}

  /部分

  /div

  脚本

  const app=new Vue({

  埃尔: #app ,

  数据:{

  p1: [ph , 18]

  }

  })

  /脚本

  运行后页面显示ph 18,控制台执行app.p1[0]=lj 。页面没有响应,因为数组只能通过拦截器调用指定的7个方法来通知外界。如果你执行app。$set(app.p1,0, pm ),页面内容就会变成pm 18。

  以上是vue检测数据变化的基本实现的详细内容。更多关于vue检测数据变化的信息,请关注我们的其他相关文章!

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: