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的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。