关于vue子组件的数据变了视图不更新的解决办法

摘要:
Vue框架使用此API定义对象的属性,其响应原则也通过通过此API自定义setter和getter来实现。通知发送后,观察者将被添加到队列中,更新将由vue统一调度。稍后,vue将执行补丁。与虚拟dom进行比较,并在当前页面组件级别进行总体更新。

原因是因为:   

vue不能检测data中数组的变动,如利用索引直接改变一个项的值的时候,利用arr.length修改数组的长度的时候, 还有由于vue2.0 使用的是object.definepropoty进行的数据监听,导致Vue不能检测对象属性的添加和删除。

解决方法:

Vue.set() 响应式新增与修改数据
此时我们需要知道Vue.set()需要哪些参数,官方API:Vue.set()

调用方法:Vue.set( target, key, value )

target:要更改的数据源(可以是对象或者数组)

key:要更改的具体数据

value :重新赋的值

 首先我们来看看vue2.0的响应式原理

目前浏览监测对象的变化的方式有Object.defineProperty和ES6的Proxy两种,在设计vue2.0的时候Proxy在浏览器的支持还并不是特别的友好,因此vue2.0是基于Object.defineProperty来实现的

Object.defineProperty(obj, prop, descriptor)

  • obj:要在其上定义属性的对象
  • prop:要定义或修改的属性的名称
  • descriptor:将被定义或修改的属性描述符
Object.defineProperty()是es5新增的方法,它的作用是可以通过该API直接在一个对象上定义一个新属性,或者修改一个对象的现有属性, 并返回这个对象。Vue框架内部大量使用了此API为对象定义属性,其响应式原理也是通过此API自定义setter与getter而完成的。

ECMAScript有两种属性

  1. 数据属性[[Configurable]]、[[Enumerable]]、[[Writable]]、[[Value]]
  2. 访问器属性[[Configurable]]、[[Enumerable]]、[[Get]]、[[Set]]

访问器属性包含两个函数get,和set,在读取访问器属性的时候,会调用getter函数,这个函数负责返回有效的值,在写入访问器属性的时候会调用setter函数冰川乳新的值,这个函数负责决定如何处理数据访问器。

var obj = {};
var a;
Object.defineProperty(obj, 'a', {
  get: function() {
    console.log('get a val'); 
    return a;
  },
  set: function(newVal) {
    console.log('set a val:' + newVal);
    a = newVal;
  }
});
obj.a;          // get a val 
obj.a = '111';  // set a val: 111
所以Object.defineProperty 把obj 的 a 属性转化为 getter 和 setter,可以实现 obj.a 的数据监控,Vue正式基于这个特性实现了响应式。 Vue 会遍历对象所有的 property,并使用 Object.defineProperty 把这些 property 全部转为 getter/setter
由于javascript的限制,Object.defineProperty()不能监测到数组的改变,vue对数组和对象使用了2种不同的方式实现,对于Object类型来说,通过劫持getter和setter来实现监测改变;对于Array来说,通过拦截器,拦截数组相关api(push、pop、shift、unshift...)来实现监测改变。所以在这里我们可以发现通过数组的下标去改变数组的某一项或者直接改变数组的长度的时候因为vue没有做这方面的处理而Object.defineProperty又监听不到所以vue是无法对此进行监听的
 

然后是观察者模式

vue是基于观察者模式来实现数据更新之后触发一系列的相关依赖来自动更新视图。那么先来了解一下什么是观察者模式,观察者模式是指一个对象维持一系列的依赖于他的对象,将有关状态变更自动的通知给他们。 观察者模式的基本要素

  • Subject (目标)
  • Observer (观察者)

定义一个收集所有依赖的容器

Watcher是一个中介的角色,数据发生变化时通知它,然后它再通知其他地方。 他就是负责具体的脏活累活

  • 1、收集依赖
  • 2、负责执行cb来更新所有的依赖

总结

vue如何实现响应式?具体实现上对象和数组稍有不同:

  • 1、对象:在create阶段,会递归的将data中的数据递归的添加get、set访问器属性,页面在mount阶段会创建全局的Watcher,并且mount阶段需要执行render渲染,会调用页面数据对应的get函数,每个数据的key都有对应的dep依赖,执行dep.depend()时会将 将dep 添加至当前watcher的subs队列中去。当页面数据更新后,调用set函数,执行通知。
  • 2、数组:在create阶段,如果是数组类型时,给会执行数组改变方法添加拦截器,同时也会给数据添加get和set访问器属性,只是数组改变时并不会触发set函数,页面在mount阶段执行render,调用数据对应的get函数,并调用childObj.dep.depend()收集watcher,(childObj.dep是什么?在初始化的data的时候会递归的将array转成observer,所以childObj.dep指的是数组array的依赖)。在array数据更新之后,会执行拦截器中的__obj__.dep.notify()执行通知,set并不会触发。

通知之后页面怎么更新渲染? 当发送通知之后,会将watcher添加至队列中由vue统一调度执行更新,后期vue将会进行patch,对比虚拟dom,以当前页面组件级别做一个整体更新。



链接:https://juejin.cn/post/6854573221526634509

免责声明:文章转载自《关于vue子组件的数据变了视图不更新的解决办法》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇PDA在扫描完条码 自动提交 的屏避方法00.充电桩的那些事儿下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

vue列表页进入详情页,返回列表项不刷新

功能 像搜索功能,在点击某项进入详情页,再回到搜索界面,如果不做特殊处理,初始化到原来的状态,在vue中可以使用keep-alive缓存搜索界面,达到数据不刷新的结果。 思路 在搜索路由对象的meta添加一个keepAlive属性,值为true,表示在路由切换的时候,会被缓存。这样一来搜索界面的数据不会被初始化。 缓存界面 keepAlive如果为true...

JS去除对象或数组中的空值('',null,undefined,[],{})

javascript去掉对象或数组中的'',null,undefined,[],{}。思路就是创建一个新的空对象,然后对传入的对象进行遍历,只把符合条件的属性返回,保留有效值,然后就相当于把空值去掉了。(可以根据注释来修改方法决定要去除哪些属性) function removeEmptyField(obj) { var newObj = {} if...

ceph ---(ceph简介)

ceph简介: Ceph是一种为优秀的性能、可靠性和可扩展性而设计的统一的、分布式文件系统。ceph 的统一体现在可以提供文件系统、块存储和对象存储,分布式体现在可以动态扩展。在国内一些公司的云环境中,通常会采用 ceph 作为openstack 的唯一后端存储来提高数据转发效率。 Ceph项目最早起源于Sage就读博士期间的工作(最早的成果于2004年发...

基于Vue的页面切换左右滑动效果

HTML文本页面: <template> <div id="app> <transition :name="direction" mode="out-in"> <!--动态获得transition 的name值--> <router-view class="app-view...

将excel中的数据转为json格式

---恢复内容开始--- 用来总结工作中碰导一些错误,可以让自己在碰到相同错误的时候不至于重新走一遍。。。。        昨天导入数据的时候,碰到了一个问题是将一个大数组里面的每一个元素中的一些不要的去提出掉,本身这些元素每一个本身也是数组,然后我去遍历大数组,又去遍历小数组,然后要赋值的条件就懵了,因为是双重循环,所以后面洗澡想起来可以用一个函数去跑内...

Vue 打包成APP后首屏出现白屏问题

  1、npm run build打包后页面全屏空白   解决位置:config/index.js文件:把assetsPublicPath: '/'改为assetsPublicPath: './' 2、npm run build打包后  底部的选项卡正常显示,但是内容白屏,只有点击一次之后才能出现   解决位置:router/index.js 里 路由设置...