vue监听方法,vue监听器原理

  vue监听方法,vue监听器原理

  本文主要介绍Vue监测数据的原理。边肖认为这很好。现在分享给大家,给大家一个参考。来和边肖一起看看吧。

  一.导言监控对象2.1为什么需要监控对象2.2与对象监控相关的API的数据代理2.3 Vue.set2.4为对象III分配多个新值。监控阵列摘要

  

目录

  首先画一个简单的图。

  我们写Vue的时候,总是对数据进行处理,把我们的目标数据写在数据里,然后在模板的差分表达式里把数据以{{xxx}}的格式渲染出来。当data中的数据发生变化时,这里的橙色线会导致差异表达式发生变化。那么问题来了,我们如何监控数据中数据的变化呢?这就涉及到Vue监测数据的问题。

  

一、引入

  

二、监测对象

  首先,写出您需要的静态页面。

  !声明文档类型

  html lang=en

  头

  meta charset=UTF-8

  更新标题/标题数据

  脚本类型=text/javascript src=./js/vue.js/script

  /头

  身体

  div id=root

  保险商实验所

  li v-for=p in persons :key=p.id

  {{p.name}} - {{p.age}}={{p.sex}}

  /李

  /ul

  /div

  脚本类型=文本/javascript

  Vue.config.productionTip=false

  const vm=new Vue({

  el: #root ,

  数据:{

  人员:[

  {id:001 ,姓名:黑猫有点绯红,年龄:20,性别:未知 },

  {id:002 ,姓名:白猫有点绯红,年龄:23,性别:男 },

  {id:003 ,姓名:一只猫有点绯红,年龄:18,性别:女 }

  ]

  }

  })

  /脚本

  /body

  /html

  现在假设有一个在页面上添加按钮的需求,通过这个按钮可以修改id为002的数据。

  Button @click=change 单击以修改白猫/button

  方法:{

  更改(){

  这个人[1]。name=白马

  这个人[1]。年龄=17岁

  这个人[1]。性别=未知

  }

  }

  逐个修改属性可以改变id为002的数据,但是这样是不是有点繁琐?能不能把这么长的修改改成一个对象?

  This.persons[1]={id:002 ,姓名:白马,年龄:17岁,性别:未知 }

  此时,点击浏览器中的按钮后,页面没有任何响应。然而出乎意料的是,在vm实例对象中,persons[1]的数据确实被更改了!

  要解决这个问题,我们可以先看另一个例子,然后通过在浏览器中输出来看具体的执行过程,了解如何监控之后再回来看这个问题。

  

2.1 为什么需要监测对象

  要理解数据监控,我们还需要理解一个前概念:数据代理。

  !声明文档类型

  html lang=en

  头

  meta charset=UTF-8

  标题监控对象/标题

  脚本类型=text/javascript src=./js/vue.js/script

  /头

  身体

  div id=root/div

  脚本类型=文本/javascript

  Vue.config.productionTip=false

  const vm=new Vue({

  el: #root ,

  数据:{

  名字:‘黑猫是一点点深红色’,

  年龄:20岁

  }

  })

  /脚本

  /body

  /html

  以前如果要访问data中的数据,可以直接通过实例对象,比如vm.name、vm.age来获取具体的值,其实这是做了数据代理之后的一种简化的编写方法。

  Vue处理过一次数据,把数据放到_data里。实例对象可以通过。_data。但是,属性的值不再是直接给出的,而是通过get方法获得,这有点类似于JAVA等面向对象语言中使用的getter方法来获得类中的私有变量。这里还有一个set方法。当数据中的数据值发生变化时,会调用set方法,导致重新解析模板,然后生成新的虚拟DOM,将新的DOM与旧的进行比较,最后更新页面。

  其实这里涉及到了源代码。本文中不考虑源代码,否则会太复杂。简单来说,其实Vue内部有这样一个方法:

  vm。_data=data=新观察者(数据)

  在Observer函数中,数据的所有属性都由Object.keys获取,形成一个数组。然后通过遍历数组,利用Object.defineProperty实现数据劫持,最后将计算的最终结果给_data。

  

2.2数据代理

  或者先去静态页面。

  !声明文档类型

  html lang=en

  头

  meta charset=UTF-8

  更新标题/标题数据

  脚本类型=text/javascript src=./js/vue.js/script

  /头

  身体

  div id=root

  H2学校名称:{{name}}/h2

  H2学校地址:{{address}}/h2

  人力资源/

  H2学生姓名:{{student.name}}/h2

  H2学生性别:{{student.sex}}/h2

  H2学生年龄:{{student.age}}/h2

  H1朋友/h1

  保险商实验所

  李v-for=(f,index)in student . friends :key= index

  {{f.name}} - {{f.age}}

  /李

  /ul

  /div

  脚本类型=文本/javascript

  Vue.config.productionTip=false

  const vm=new Vue({

  el: #root ,

  数据:{

  名称:“麻省理工学院”,

  地址:“UUU”,

  学生:{

  姓名:“汤姆”,

  年龄:20,

  朋友:[

  {姓名:杰克,年龄:21},

  {姓名:“玛丽”,年龄:20}

  ]

  },

  }

  })

  /脚本

  /body

  /html

  您可能会注意到,模板中出现的性别实际上并不存在于数据中。当输出一个对象中不存在的属性值时,会输出undefined,但是Vue不会显示处理后的undefined值,也就是说此时页面上的学生性别后面有一个null值,控制台不会出现错误。现在提出一个需求,如果需要给学生增加一个新的性别属性。要求是不能改变数据中已有的数据,也就是不能直接把性别放入数据中。

  根据前面介绍的_data,我们可以尝试直接通过_data绑定性别属性。然后发现页面上没有渲染。其实这里的问题有点类似于2.1中的问题。以下分析。

  让我们先打印虚拟机的数据。从下图中可以清楚的看到,性别属性名和未知属性值被成功添加到学生对象中。但是在上面看,下面的get和set方法中并没有针对sex的方法,也就是说这个添加的属性并没有成为响应式数据。

  要解决这个问题,我们可以使用Vue提供的API,也就是Vue.set()方法,让后面添加的数据也变成响应式数据。该方法的第一个参数target指示向谁添加数据,第二个参数key指示属性名,第三个参数属性值。

  此时,我们不仅可以改变_data中的属性,还可以被监控,通过Vue.set(vm)改变页面中的数据。_data.student,性别,未知)。还有一个api也有同样的效果,就是vm。$set,用法和Vue.set()一样,参数也一样,vm。$set(vm。_data.student,性别,未知)。通过这两种方法添加的数据可以成为响应数据。

  实现功能后,可以考虑优化缩写。作为数据代理,vm.student===vm。_data.student,可以缩写为Vue.set(vm.student,性别,未知)。

  接下来,在实际的编码中验证浏览器中的想法,假设性别属性是通过单击一个按钮添加的。这里不做过多描述,直接粘贴代码。

  !声明文档类型

  html lang=en

  头

  meta charset=UTF-8

  更新标题/标题数据

  脚本类型=text/javascript src=./js/vue.js/script

  /头

  身体

  div id=root

  Button @click=addSex 单击按钮添加性别/button

  H2学校名称:{{name}}/h2

  H2学校地址:{{address}}/h2

  人力资源/

  H2学生姓名:{{student.name}}/h2

  H2学生性别:{{student.sex}}/h2

  H2学生年龄:{{student.age}}/h2

  H1朋友/h1

  保险商实验所

  李v-for=(f,index)in student . friends :key= index

  {{f.name}} - {{f.age}}

  /李

  /ul

  /div

  脚本类型=文本/javascript

  Vue.config.productionTip=false

  const vm=new Vue({

  el: #root ,

  数据:{

  名称:“麻省理工学院”,

  地址:“UUU”,

  学生:{

  姓名:“汤姆”,

  年龄:20,

  朋友:[

  {姓名:杰克,年龄:21},

  {姓名:“玛丽”,年龄:20}

  ]

  },

  },

  方法:{

  addSex(){

  //在方法中,这一点是vm实例对象

  //这里也可以写成这样。$set(this.student, sex , male )

  Vue.set(this.student, sex , male )

  }

  }

  })

  /脚本

  /body

  /html

  但是,这种方法有一定的局限性。当添加成功时,它被设置为data中的student对象。如果直接设置为数据对象呢?例如,假设您需要在这里添加一个新的属性学校日期时间。如果您仍然使用Vue.set方法,将会报告一个错误。

  可以看出,这个方法只能用来给一个响应对象(比如这里的data.student)添加一个新的属性,并触发视图更新。因为Vue检测不到普通的新属性。

  

2.3 对象监测相关API之Vue.set

  有时您可能需要为现有对象分配多个新属性,例如使用Object.assign()或_。扩展()。但是,以这种方式添加到对象的新属性不会触发更新。因此,在这种情况下,您应该创建一个新对象,将原始对象和该对象的属性混合在一起。

  例如,我想给学生添加以前不存在的身高和体重属性。我可以这样做:

  const add={height: 180, weight: 150}

  this.student=Object.assign({},this.student,add)

  将原始对象与新对象合并,并将其分配给一个空的新对象,然后将该对象分配给this.student最终数据可以相应地添加给学生。

  

2.4为对象赋多个新值

  还是先去静态页面。

  !声明文档类型

  html lang=en

  头

  meta charset=UTF-8

  更新标题/标题数据

  脚本类型=text/javascript src=./js/vue.js/script

  /头

  身体

  div id=root

  Button @click=addSex 单击按钮添加性别/button

  H2学校名称:{{name}}/h2

  H2学校地址:{{address}}/h2

  人力资源/

  H2学生姓名:{{student.name}}/h2

  H2学生性别:{{student.sex}}/h2

  H2学生年龄:{{student.age}}/h2

  H1朋友/h1

  保险商实验所

  李v-for=(f,index)in student . friends :key= index

  {{f.name}} - {{f.age}}

  /李

  /ul

  H1霍比/h1

  保险商实验所

  李v-for=(h,index)in student . hobby :key= index

  {{h}}

  /李

  /ul

  /div

  脚本类型=文本/javascript

  Vue.config.productionTip=false

  const vm=new Vue({

  el: #root ,

  数据:{

  名称:“麻省理工学院”,

  地址:“UUU”,

  学生:{

  姓名:“汤姆”,

  年龄:20,

  朋友:[

  {姓名:杰克,年龄:21},

  {姓名:“玛丽”,年龄:20}

  ],

  爱好:[吃,睡,打豌豆]

  },

  },

  方法:{

  addSex(){

  这个。$set(this.student, sex , male )

  }

  }

  })

  /脚本

  /body

  /html

  打印vm后。_data在控制台中,我们可以清楚地看到,对于student中的hobby数组,该数组整体上有get和set,它们是有响应的。但是数组中的元素没有响应,只是简单的挂在数组中,这也是为什么在2.1中,当我们试图重新分配数组的索引下标时,页面上没有响应。如果你把爱好数组改成一个对象,再打印一次,你会发现对象里的属性是有反应的。由此我们可以大致猜测,在Vue中,如果要通过索引来修改数组中的值,需要使用一些特殊的方法。

  方法从何而来?现在我们可以看看Vue文档里说了什么。在文档列表渲染-数组更新检测-更改方法的页面中,有这样一段话:

  Vue包装了被监视阵列的更改方法,因此它们也将触发视图更新。这些包装方法包括:

  push()pop()shift()unshift()splice()sort()reverse()

  要修改数组中的数据,不妨试试以上七种方法。看到这些方法,你可能会想到Array原型链上的方法,但在这里并不完全正确。Vue将这些方法包装一次。Vue解析这些方法时,第一步仍然是正常调用数组原型链中的方法,第二步是再次解析模板。这就是为什么使用这些方法可以触发视图更新,因为再次解析模板后,会生成一个新的虚拟DOM来对比新旧DOM,最后更新页面。这个想法可以从VM的判断中得到印证。_ data . student . hobby . push===array . prototype . push为false。

  比如这里,为了学习,想修改《爱好》里的“打豆豆”,应该怎么做?

  在接触这些知识点之前,我会用下面的代码,后面是一个错误的渲染。更改数据后,页面没有更新。

  this . student . hobby[2]= learning

  接下来,我们尝试两种方法。先试试刚才介绍的数组运算法。

  This.student.hobby.splice(2,3,“学习”)

  接下来试试之前介绍的Vue.set方法。

  这里补充一下,在2.3中,我们介绍了当使用这个方法修改一个对象中的值时,方法的第二个参数是属性名;在数组中使用此方法时,第二个参数应该是数组中元素的下标。

  这个。$set(this.student.hobby,2, learning )

  两种方法都可以成功修改hobby中的数据,并更新到页面。

  一般来说,不能通过数组的索引值赋值。但是你可以改变数组本身的指向。正如我们在前面的图片中看到的,爱好数组本身是有响应的,可以通过get和set进行监控。例如,在业务逻辑中,filter用于过滤数组,然后赋给数据中已经存在的数组。这里,我们可以再次查看文档中替换数组一节的介绍。filter、concat、slice等方法不改变原始数组,但总是返回一个新数组。使用change方法时,可以用新数组替换旧数组。

  

三、监测数组

  本文到此为止。希望能帮到你,也希望你能多关注我们的更多内容!

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

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