前言

该问题只存在vue2, 基于Object.defineProperty的特性,vue3中的proxy已经解决了该问题,但也存在兼容性问题,例如IE系统任意版本都不支持.

vue2是如何追踪数据变化形成响应

口水版:页面一进来会扫描数据,实行类似双向绑定,当初始时没有设定好属性,后面添加新属性,会存在数据中,但页面并不会进行响应同步(MVVM)
专业版 :
当你把一个普通的 JavaScript 对象传入 Vue 实例作为 data 选项,Vue 将遍历此对象所有的 property,并使用 Object.defineProperty 把这些 property 全部转为 getter/setter。Object.defineProperty 是 ES5 中一个无法 shim 的特性,这也就是 Vue 不支持 IE8 以及更低版本浏览器的原因。
这些 getter/setter 对用户来说是不可见的,但是在内部它们让 Vue 能够追踪依赖,在 property 被访问和修改时通知变更。
每个组件实例都对应一个 watcher 实例,它会在组件渲染的过程中把“接触”过的数据 property 记录为依赖。之后当依赖项的 setter 触发时,会通知 watcher,从而使它关联的组件重新渲染。

vue2响应的注意点

由于 JavaScript 的限制(其实是Object.defineProperty),Vue 不能检测数组和对象的变化。
比方日常开发中遇到需要在对象中添加新的属性,属性已经存在数据中,但页面并不会立即更新.
如下,点击按钮时,‘山竹’会变成’杀生丸’,但age会在数据中,不会立刻出现在页面

 <div id='app'><p>{{ user.name }}</p><p>{{ user.age }}</p><button @click='changeName'>改变data中name属性</button><button @click='addAge'>给data添加age属性</button></div><script>let vm = new Vue({el: '#app',data() {return {user: { name: '山竹' }}},methods: {changeName() {//如果是一开始就设定属性,绑定页面后,点击会触发this.user.name = '杀生丸'},addAge() {//非响应this.user.age = 18console.log(this.user);//age: 18,name: "杀生丸"}}})</script>

解决方案

其解决方法多种多样,这里举例几种,但根本的中心点就是使对象/数组发生变更,触发watcher重新渲染

对象

方案一:初始时设定

如下,在一开始的时候就预设可能需要添加的属性, age: ‘’

<div id='app'><p>{{ user.name }}</p><p>{{ user.age }}</p><button @click='changeName'>改变data中name属性</button><button @click='addAge'>给data添加age属性</button></div><script>let vm = new Vue({el: '#app',data() {return {user: { name: '山竹', age: '' }}},methods: {changeName() {//如果是一开始就设定属性,绑定页面后,点击会触发this.user.name = '杀生丸'},addAge() {this.user.age = 18console.log(this.user);//age: 18,name: "杀生丸"}}})</script>

方案二:调用Vue.set方法

Vue.set(原对象,需要设置的新属性, 需要设置的新值)

 <div id='app'><p>{{ user.name }}</p><p>{{ user.age }}</p><button @click='changeName'>改变data中name属性</button><button @click='addAge'>给data添加age属性</button></div><script>let vm = new Vue({el: '#app',data() {return {user: { name: '山竹' }}},methods: {changeName() {//如果是一开始就设定属性,绑定页面后,点击会触发this.user.name = '杀生丸'},addAge() {// Vue.set(原对象/数组,需要设置的新属性, 需要设置的新值)Vue.set(this.user, 'age', 18)console.log(this.user);//age: 18,name: "杀生丸"}}})</script>

方案三:创建一个新的对象,替换原对象

这种方法可以用于需要添加多个新属性,再把原对象与新属性合并到新对象中
Object.assign(目标对象,原对象, 新属性)

<div id='app'><p>{{ user.name }}</p><p>{{ user }}</p><button @click='changeName'>改变data中name属性</button><button @click='add'>给data添加新属性</button></div><script>let vm = new Vue({el: '#app',data() {return {user: { name: '山竹' }}},methods: {changeName() {//如果是一开始就设定属性,绑定页面后,点击会触发this.user.name = '杀生丸'},add() {// Object.assign方法的第一个参数是目标对象,后面的参数都是源对象// Object.assign(目标对象,原对象, 新属性)this.user = Object.assign({}, this.user, { skill: '铁碎牙', age: 18 })console.log(this.user);//age: 18,name: "山竹",skill: "铁碎牙"}}})</script>

数组

方案一:切割替换原数组

//vm.items.splice(下标, 1, 新数组)
vm.items.splice(indexOfItem, 1, newValue)

方案二:Vue.set

//Vue.set(原数组,需要设置的下标, 需要设置的新值)
Vue.set(vm.items, indexOfItem, newValue)

深入vue2响应式原理,在对象或数组新增属性无响应解决方法相关推荐

  1. Vue3的响应式原理解析

    Vue3的响应式原理解析 Vue2响应式原理回顾 // 1.对象响应化:遍历每个key,定义getter.setter // 2.数组响应化:覆盖数组原型方法,额外增加通知逻辑 const origi ...

  2. matlabeig函数根据什么原理_vue3.0 源码解析二 :响应式原理(下)

    一 回顾上文 上节我们讲了数据绑定proxy原理,vue3.0用到的基本的拦截器,以及reactive入口等等.调用reactive建立响应式,首先通过判断数据类型来确定使用的hander,然后创建p ...

  3. vuejs视图不能及时更新的问题 ,深入响应式原理

    最近三个多月,我和我的同事一起用vuejs 做公司的项目管理系统,因为是第一次用这种双向绑定的框架,难免遇到一些问题. 在做项目时,发现数据并没有实时更新,比如说你用element-ui的时间控件或者 ...

  4. Vue 2.x 响应式原理与双向绑定

    Vue实例 Vue会把data中的数据成员注入到Vue的实例中去,并转成getter/setter访问器属性. 这样的目的是: 1.我们能够通过 this.xxx(this.属性名)的方式进行调用. ...

  5. vue 存储对象 不要监听_Vue源码解析----响应式原理

    从很久之前就已经接触过了angularjs了,当时就已经了解到,angularjs是通过脏检查来实现数据监测以及页面更新渲染.之后,再接触了vue.js,当时也一度很好奇vue.js是如何监测数据更新 ...

  6. Vue2.0 —— 由设计模式切入,实现响应式原理

    Vue2.0 -- 由设计模式切入,实现响应式原理 <工欲善其事,必先利其器> 既然点进来了,麻烦你看下去,希望你有不一样的收获. 大家好,我是vk,好久不见,今天我们一起来盘一盘关于 V ...

  7. vue2和vue3响应式原理

    vue2响应式原理:核心使用Object.defineProperty给属性定义get和set方法 注意:对象的多次递归,针对数组需要重写数组方法 函数劫持:把函数内部进行重写同时继续调用老的方法,在 ...

  8. Vue2的响应式原理

    --------Vue2响应式原理---------- 原理:通过数据劫持 defineProperty + 发布订阅者模式,当 vue 实例初始化后 observer 会针对实例中的 data 中的 ...

  9. Day 05- Vue3 Vue2响应式原理

    Vue2的响应式 核心:通过 Object.defineProtytype() 对对象的已有属性值的读取和修改进行劫持: 数据劫持  --> 给对象扩展属性 -->  属性设置 实现原理: ...

最新文章

  1. Squid配置二级代理(父代理)
  2. leetcode算法题--最佳买卖股票时机含冷冻期★
  3. Servlet优化之BaseServlet
  4. 【2016年第6期】数据产品在线定制平台的探索实践
  5. windows软件设置快捷键
  6. python计算最大回撤_最大回撤线性算法实现
  7. 高精度地图的学习笔记
  8. mysql 执行查询_MySQL执行一个查询的过程
  9. dell服务器修改sata,Dell poweredge r210进BIOS改动磁盘控制器(SATA Controller)接口模式...
  10. Linux内核学习路线 ,应从入门到深入,学内核就来零声教育
  11. Java全栈开发---Java ERP系统开发:商业ERP(十三)CXF框架,物流BOS系统开发
  12. Linux上如何安装微信! 或登录网页版微信提示:为了你的帐号安全,此微信号不能登录网页微信。你可以使用Windows微信或Mac微信在电脑端登录。
  13. 山海经2服务器维护时间,山海经异兽录多久出一次新服 | 手游网游页游攻略大全...
  14. 【已解决】微信内置浏览器清缓存
  15. Ubuntu下添加开机启动项的2种方法
  16. mysql 3306无法访问_Mysql 3306端口无法被远程机器访问
  17. java输出数组(java输出数组)
  18. 1.6在Ubuntu安装QT5.14.2
  19. Polar SCL的C语言实现
  20. 图形学基础 | mtl文件详解

热门文章

  1. [深入理解Android卷二 全文-第三章]深入理解SystemServer
  2. 网络人远程控制软件控制速度提高诀窍
  3. 拿什么拯救你,学计算机的男生!
  4. vue3中require报错 require is not defined
  5. Cisco wlc 3504 choose country code
  6. 极光推送JPush---自定义提示音
  7. 微信小程序+.NET(十四) 悦听小说小程序(待续)
  8. background-image和img的区别
  9. 多功能车载DVD智能导航平台
  10. 浅析GRE协议(通用路由封装协议)