宝哥软件园

详细说明Vue中数组和对象改变后视图不刷新的问题

编辑:宝哥软件园 来源:互联网 时间:2021-08-29

Vue数据响应原理

官方的解释很明确:

当您将一个普通的JavaScript对象传递给Vue实例的数据选项时,Vue将遍历这个对象的所有属性,并使用Object.defineProperty将所有这些属性变成getter/setter。Object.defineProperty是ES5中无法填补的特性,这也是Vue不支持IE8和更早版本浏览器的原因。用户看不到getter/setter,但在内部,他们让Vue跟踪依赖关系,并在属性被访问和修改时通知更改。这里需要注意的问题是,当浏览器控制台打印数据对象时,getter/setter的格式是不同的,所以您可能需要安装vue-devtools来获得更友好的检查界面。每个组件实例都有一个对应的观察器实例对象,该对象在组件呈现过程中将属性记录为依赖项,然后当调用依赖项的设置器时,它会通知观察器重新计算,以便更新其关联的组件。

论吸气剂和设置剂的局限性

官方文件解释的太多了,说到底,数据的变化必须能够触发set方法,否则就无法响应数据的变化。然后,我们来看看set方法什么时候会被触发,什么时候不会被触发。

var person={ default name : ' Tom ',get name(){ return this . default name },Set name (val) {this。默认名称=val console . log(' set trigged ')} }这里我们定义了一个名为person的对象,我们通过get/set来控制名称,可以看到如果set被触发,它会打印出那个set trigged。

人。姓名='汤姆'人。name=123=setperson.name=123被触发。我们可以看到,我们可以通过直接修改名称来触发set。

person . name={ name : ' Tom ' }=set person。姓名={name3360' Tom'}人。名字。name=123123=不打印任何信息,表示修改name的属性值不会触发set方法。Person.name.sex=333=未打印任何信息,表明添加name的属性值并未触发set方法。Delete person.name.name=不打印任何信息,表示删除name的属性值不会触发set方法。object . defineperproperty(person。name,' name ',{value: 4444})=不打印任何信息,这意味着set方法不是由对象触发的。定义属性。当名称是一个对象时,我们没有通过修改、添加或删除名称的属性值来触发set方法。

Person.name=[1,2,3]=setperson.name.push(4)=不打印任何信息,表示push方法没有触发set方法。说明数组的推方法不能触发集合方法,pop、shift、unshift等原生数组方法也不能触发集合。

解决办法

由于现代JavaScript(以及过时的Object.observe)的限制,Vue无法检测对象属性的添加或删除。由于Vue在初始化实例时会对属性执行getter/setter转换,因此属性必须存在于数据对象中,这样Vue才能对其进行转换,以便它能够做出响应。例如:

var VM=NewVue({ data : { a :1 } })/` VM . a '是有响应的VM . b=2/` VM . b '是无响应的Vue。不允许在已创建的实例上动态添加新的根级反应属性。但是,它可以使用Vue.set(对象、键、值)方法向嵌套对象添加响应属性:

你也可以使用虚拟机。$set实例方法,也是全局vue.set方法的别名:

这个。$ set(这个。2)有时你想给一个现有的对象添加一些属性,例如,使用Object.assign()或_。extend()方法添加属性。但是,添加到对象的新属性不会触发更新。在这种情况下,您可以创建一个新对象,并让它包含原始对象的属性和新属性:

//替换` Object.assign (this.someobject,{a: 1,b: 2})` this.someobject=Object.assign({ },this . some object,{a: 1,b : 2 })引入object . assign()

阵列更新检测

变分法

记得我们测试过push等方法不能触发set方法,所以Vue给我们定义了一系列的变异方法,可以直接使用:

-push()-pop()-shift()-unshift()-split()-sort()-reverse()替代方法

突变方法,顾名思义,改变这些方法调用的原始数组。相比之下,也有非突变方法,如filter()、concat()和slice()。这些不会改变原始数组,但总是返回一个新数组。使用非突变方法时,可以用新数组替换旧数组:

example 1 . items=example 1 . items . filter(function(item){ return item . message . match(/foo/)})您可能会认为这将导致Vue丢弃现有的DOM并重新呈现整个列表。幸运的是,事实并非如此。Vue已经实现了一些智能和启发式的方法来最大限度地重用DOM元素,所以用包含相同元素的数组替换原始数组是一个非常高效的操作。

需要注意的事项

由于JavaScript的限制,Vue无法检测到以下已更改的数组:

当您使用索引直接设置项目时,例如:vm.items[indexOfItem]=newValue

修改数组长度时,例如:vm.items.length=newLength

为了解决第一个问题,以下两种方法可以达到与vm.items[indexOfItem]=newValue相同的效果,并且还会触发状态更新:

//vue . setvue . set(example 1 . items,item的索引,新值)//array . prototype . splice example 1 . items . splice(item的索引,1,新值)为了解决第二个问题,可以使用splice:

示例1.items.split(新长度)引用

深度响应原则官方文件Object.assign方法介绍getter/setter方法介绍对象响应问题

以上就是本文的全部内容。希望对大家的学习有帮助,支持我们。

更多资讯
游戏推荐
更多+