当前位置: 首页 > Web前端 > vue.js

7种Vue数据更新但页面没有更新的情况总结和扩展总结

时间:2023-03-31 23:10:46 vue.js

如果你发现自己需要在Vue中做一个强制更新,99.9%的情况下,你在某个地方做错了。1、Vue在创建实例时无法检测到数据中不存在的属性。原因:由于Vue会在实例初始化时对属性进行getter/setter转换,所以属性必须存在于数据对象上,Vue才能将其转换为响应式。的。场景:varvm=newVue({data:{},//页面不会改变template:'

{{message}}
'})vm.message='Hello!'//`vm.message`不是响应式解决方案:varvm=newVue({data:{//将a,b声明为空字符串message:'',},template:'
{{message}}
'})vm.message='你好!'2.Vue无法检测对象属性的增删原因:官方-由于JavaScript(ES5)的限制,Vue.js无法检测对象属性的增删delete。因为Vue.js在初始化实例时会将属性转换为getters/setters,所以属性必须在数据对象上,以便Vue.js对其进行转换,使其具有响应性。Scene:varvm=newVue({data:{obj:{id:001}},//页面不会改变template:'
{{obj.message}}
'})vm.obj.message='hello'//无响应deletevm.obj.id//无响应解决方案://动态添加-Vue.setVue.set(vm.obj,propertyName,newValue)//动态添加-vm.$setvm.$set(vm.obj,propertyName,newValue)//动态添加多个//而不是Object.assign(this.obj,{a:1,b:2})this.obj=Object.assign({},this.obj,{a:1,b:2})//动态移除-Vue.deleteVue.delete(vm.obj,propertyName)//动态移除-vm.$deletevm.$delete(vm.obj,propertyName)3.Vue无法检测到通过数组索引直接修改数组项原因:官方-由于JavaScript的限制,Vue无法检测到数组和对象的变化;游玉玺-性能成本与用户体验不成正比。场景:varvm=newVue({data:{items:['a','b','c']}})vm.items[1]='x'//不是响应式解决方案://Vue.setVue.set(vm.items,indexOfItem,newValue)//vm.$setvm.$set(vm.items,indexOfItem,newValue)//Array.prototype.splicevm.items.splice(indexOfItem,1,newValue)扩展:Object.defineProperty()可以监听数组的变化Object.defineProperty()可以监听数组的变化。但是给数组增加一个属性(索引)是不会检测到数据变化的,因为新增加的数组的下标(索引)是监听不到的,删除一个属性(索引)也是一样的。场景:vararr=[1,2,3,4]arr.forEach(function(item,index){Object.defineProperty(arr,index,{set:function(value){console.log('triggersetter')item=value},get:function(){console.log('triggergetter')returnitem}})})arr[1]='123'//triggersetterarr[1]//triggergetterreturnvalue"123"arr[5]=5//不会触发setter和getter4.Vue无法监听直接修改数组长度的变化原因:官方-由于JavaScript的限制,Vue无法检测到数组和对象的变化;游鱼溪-性能成本与获得的用户体验不成正比。场景:varvm=newVue({data:{items:['a','b','c']}})vm.items.length=2//不是响应式解决方案:vm.items。拼接(新长度)5。在执行异步更新之前,DOM数据不会发生变化。原因:Vue在更新DOM时异步执行。只要检测到数据变化,Vue就会打开一个队列,缓冲所有发生在同一个事件循环中的数据变化。如果同一个观察者被多次触发,它只会被推入队列一次。这种缓冲时的重复数据删除对于避免不必要的计算和DOM操作非常重要。然后,在下一个事件循环“tick”中,Vue刷新队列并执行实际(去重)工作。Vue内部尝试使用原生的Promise.then、MutationObserver和setImmediate来实现异步队列。如果执行环境不支持,它将使用setTimeout(fn,0)代替。场景:{{message}}
varvm=newVue({el:'#example',data:{message:'123'}})vm.message='newmessage'//改变数据vm.$el.textContent==='newmessage'//falsevm.$el.style.color='red'//页面不变解决方案:varvm=newVue({el:'#example',data:{message:'123'}})vm.message='newmessage'//更改数据//使用Vue.nextTick(callback)回调将在DOM更新完成后调用Vue.nextTick(function(){vm.$el.textContent==='newmessage'//truevm.$el.style.color='red'//文字颜色变成红色})扩展:异步更新带来的数据响应误会{{message.text}}
varvm=newVue({el:'#example',data:{message:{},}})vm.$nextTick(function(){this.message={}this.message.text='我已经更新了!'})在上面的代码中,我们在数据对象中声明了一个空的message对象,然后在下一个DOM之后更新周期结束在触发的异步回调中,执行了以下两段代码:this.message={};this.message.text='I'mupdating!'这里,模板已经更新,页面终于会显示我已经更新了!.模板已经更新,应该是响应式的,如果你这么认为那你就进入误区了。一开始我们只是在data对象中声明了一个空的message对象,没有text属性,所以text属性是没有响应的。但是模板居然已经更新了,这是怎么回事呢?那是因为Vue.js的DOM更新是异步的,即当setter操作发生时,指令不会立即更新,指令的更新操作会有延迟。当指令更新实际执行时,文本属性已经被赋值,所以指令在更新模板时得到新值。模板中的每个指令/数据绑定都有一个相应的观察者对象,该对象在评估期间将属性记录为依赖项。之后调用依赖的setter时,会触发watcher重新计算,也会导致其关联指令更新DOM。具体过程如下:whenthis.message={};被执行时,setter被调用。Vue.js跟踪消息依赖的setter被调用后,会触发watcher重新计算。this.message.text='我更新了!';为文本属性分配一个值。异步回调逻辑执行完成后,会导致其关联指令更新DOM,指令更新开始执行。所以真正触发模板更新的操作是this.message={};这句话造成的,因为触发了setter,所以就看上面的例子,具有响应式特性的数据只是消息层,其动态添加的属性是不可用的。对应上面第二点——Vue无法检测对象属性的增减6.循环嵌套层次太深,视图不更新?我在网上看到有人说数据更新的层级太深,导致没有数据更新或者更新慢,导致尝试不更新?由于我没有遇到过这种情况,当我尝试重现这种场景时,发现并没有出现上述情况,所以这一点我就不过多描述了(如果有人在真实场景中遇到过这种情况留言)。有人针对上述情况给出的解决方案是使用强制更新:如果你发现自己需要在Vue中进行强制更新,99.9%的情况下,你在某个地方做错了。vm.$forceUpdate()7.扩展:当路由参数改变时,页面不更新(数据不更新)。展开一个由于路由参数变化导致页面不更新的问题。页面不更新的本质是数据没有更新。原因:当路由视图组件引用同一个组件时,当路由参与发生变化时,组件无法更新,也就是我们常说的页面无法更新的问题。场景:
  • ToFoo
  • 到巴兹
  • 到巴兹
constHome={template:`
{{message}}
`,data(){return{message:this.$route.params.name}}}constrouter=newVueRouter({mode:'history',routes:[{path:'/home',component:Home},{path:'/home/:name',component:Home}]})newVue({el:'#app',router})在上面的代码中,我们在路由构建选项routes中配置了一个动态路由'/home/:name',它们共享一个路由组件Home,意味着他们重用了RouterView。路由切换时,页面只会渲染第一个路由匹配的参数,后面切换路由时消息不会改变。解决方案:解决方案有很多,这里只介绍我常用的几种。通过watch监控$route的变化。constHome={template:`
{{message}}
`,data(){return{message:this.$route.params.name}},watch:{'$route':函数(){this.message=this.$route.params.name}}}...newVue({el:'#app',router})将key属性绑定到,这样Vue会认为这是不同的。缺点:如果从/home跳转到/user等路由,我们不用担心组件更新,所以此时key属性是多余的。...
参考:Vue响应式数据更新的误区-https://github.com/xiaofuzi/d...[樱桃小丸子的城堡]-https://www.cnblogs.com/youho...