前言:

在平常的开发中,经常会在vue中用到对象数组,如渲染一个小区的列表,数据结构可能如下所示:

CommunityList: [

{

_id: '',

community_code: '',

community_name: '',

...

},

...

]

当需要实现选择某几个小区加入收藏列表的时候,页面上往往需要增加el-checkbox来勾选,在数据结构上需要增加一个类似relation属性来标志该小区是否被选择。

所以在从接口拿到数据的时候需要在数据上增加relation属性,处理方式可能如下所示:

/** result是从接口获取的数据 **/

if (result && result.retCode === 0) {

this.communityList = result.list.map(item => {

item.relation = false;

return item;

})

}

当你碰巧在处理数据之前先将result.list赋值给了另一个实例属性,如下所示:

/** result是从接口获取的数据 **/

if (result && result.retCode === 0) {

this.communityListCache = result.list; // 新增的代码

this.communityList = result.list.map(item => {

item.relation = false;

return item;

})

}

那么此时el-checkbox的表现可能会不太正常,如下所示:

点击时状态不会立马改变,而是等鼠标移开了才改变

下面两个图均是在el-checkbox为灰色状态下点击的结果,一个为true,另一个却是false

分析:

经过打断点分析发现某些属性并不是像其它属性一样的表现

如这里的relation属性(el-checkbox绑定的就是该属性),不像下面的_id属性所表现的一致,_id属性所表现的就是正常的被vue监听的状态,很明显relation并没有被vue监听,问题就出现在新增的代码那里。

通过分析vue的源代码可知,实例属性被赋值的时候会使用Object.defineProperties方法将其转化为可被监听的属性,如果赋值了一个数组,也会将数组转化为可被监听的对象,且会深入内部监听如下:

截取自vue源代码中的部分片段:

export class Observer {

value: any;

dep: Dep;

vmCount: number; // number of vms that have this object as root $data

constructor (value: any) {

this.value = value

this.dep = new Dep()

this.vmCount = 0

def(value, '__ob__', this)

if (Array.isArray(value)) {

if (hasProto) {

protoAugment(value, arrayMethods)

} else {

copyAugment(value, arrayMethods, arrayKeys)

}

this.observeArray(value) // 当为数组时,转化数组

} else {

this.walk(value)

}

}

...

/**

* Observe a list of Array items.

*/

observeArray (items: Array) {

for (let i = 0, l = items.length; i < l; i++) {

observe(items[i]) // 逐级转化

}

}

}

又因为js中引用类型只是指向实际数据的类似指针的结构,此时this.communityListCache和result.list在内存中实际就是指向同一个地址,当vue转化this.communityListCache的时候实际就是转化了result.list

this.communityListCache = result.list; // 新增的代码

vue会在result.list中新增__ob__这个属性来标志已经被转化过了,如下图所示:

由于relation是在之后才新增的属性,而在vue转化的时候,如果对象有__ob__属性,则表示已经被转化过了,不会再次去处理,如下:

截取自vue源代码中的部分片段:

/**

* Attempt to create an observer instance for a value,

* returns the new observer if successfully observed,

* or the existing observer if the value already has one.

*/

export function observe (value: any, asRootData: ?boolean): Observer | void {

if (!isObject(value) || value instanceof VNode) {

return

}

let ob: Observer | void

if (hasOwn(value, '__ob__') && value.__ob__ instanceof Observer) { // 判断是否本来就存在__ob__属性,如果存在就直接赋值,不做处理

ob = value.__ob__

} else if (

shouldObserve &&

!isServerRendering() &&

(Array.isArray(value) || isPlainObject(value)) &&

Object.isExtensible(value) &&

!value._isVue

) {

ob = new Observer(value)

}

if (asRootData && ob) {

ob.vmCount++

}

return ob

}

这样后面新增的relation属性实际就是没有被vue所监听的属性,自然就不会响应变化。

解决办法:

1、在完全处理好原始数据后再赋值给其它的实例属性,如下:

/** result是从接口获取的数据 **/

if (result && result.retCode === 0) {

// this.communityCache = result.list; // 原始代码

this.communityList = result.list.map(item => {

item.relation = false;

return item;

});

this.communityCache = result.list; // 新增的代码

}

2、由于接口返回的数据一般没有包涵特殊类型,所以在赋值之前进行简单的深拷贝即可,这样的话,这两个变量就不是指向同一个对象,也就不会相互影响:

/** result是从接口获取的数据 **/

if (result && result.retCode === 0) {

// this.communityCache = result.list; // 原始代码

this.communityCache = JSON.parse(JSON.stringify(result.list)); // 新增代码

this.communityList = result.list.map(item => {

item.relation = false;

return item;

});

this.communityCache = result.list; // 新增的代码

}

注:个人总结,如有不对,还望指正,谢谢!

vue 数组对象提取_vue中使用对象数组的最佳实践相关推荐

  1. java 数组对象长度_Java中的数组长度:关于Java中数组长度的所有信息

    Java中的数组可以包含多个元素,这取决于对象是如何创建的.为了让用户执行不同的操作,必须知道数组的长度.这篇关于"Java中的数组长度"的文章旨在让我们熟悉用于获取数组长度的操 ...

  2. 对象数组空指针异常说明——C#中使用对象数组必须分别为其开辟空间

    l  场景 定义一个学生类,包含字段(学号,姓名,语文成绩,数学成绩,英语成绩).属性(总成绩).三个方法分别为(求平均分.数学平均分.语文平均分). 要求:在main()方法中,定义一个学生类型的数 ...

  3. vue 传递 对象 路由_vue中路由参数传递可能会遇到的坑

    前言 vue中路由跳转传参数有多种,自己常用的是下面的几种 通过router-link进行跳转 通过编程导航进行路由跳转 本文主要给大家介绍了关于vue路由参数传递遇到的一些坑,分享出来供大家参考学习 ...

  4. JavaScript数组对象教程–如何使用JS数组方法创建,更新和遍历对象

    On average I work with JSON data 18 times a week. And I still need to google for specific ways to ma ...

  5. 在ASP.NET Web API中返回错误的最佳实践

    本文翻译自:Best practice to return errors in ASP.NET Web API I have concerns on the way that we returns e ...

  6. Java 中处理 Exception 的最佳实践

    Java 中处理 Exception 的最佳实践 在Java中处理异常并不是一个简单的事情.不仅仅初学者很难理解,即使一些有经验的开发者也需要花费很多时间来思考如何处理异常,包括需要处理哪些异常,怎样 ...

  7. vue如何获取数组中的键值_vue中操作数组的相关方法

    1,锁定数组的长度(只读模式)[ Array.join() ] 2.将数组合并成字符串(返回字符串)[ Array.join() ] 3.返回逆序数组(倒叙排列数组)[ Array..reverse( ...

  8. vue 监听map数组变化_vuex state中的数组变化监听实例

    前言 首先,因为我有一个需求就是vue组件中有一组多选框,选中多选框的内容,要在另一个组件中进行视图更新,这个就设计的兄弟组件之间的通信了,兄弟组件之前通信我首先选用的vuex这个解决办法. 问题 v ...

  9. 【关于js数组对象一道题】将数组对象中的英文属性名替换为中文属性名

    将数组对象中的英文属性名替换为中文属性名 const arr = [{name: '张三', age: 18, address: '湖北'}, {name: '李四', age: 18, addres ...

最新文章

  1. arkit与现实世界距离比_如何使用ARKit和Pusher构建实时增强现实测量应用程序
  2. Android应用程序窗口(Activity)的测量(Measure)、布局(Layout)和绘制(Draw)过程分析(上)...
  3. 爬取智联招聘(面向对象)
  4. 成功解决 \tensorflow\…\datasets\mnist.py:290: DataSet.__init__ (from tensorflow.contrib.learn.python.lea
  5. php+判断时间是昨天,用php判断时间戳来输出刚刚,分钟前,小时前昨天和时间...
  6. 为什么余额宝要不断限制用户购买?
  7. 弯下腰,拾起你无价的尊严
  8. 树莓派上FFMPEG/VLC播放海康网络摄像仪视频
  9. php post重复提交session,PHP加Session防止表单重复提交的解决方法
  10. 【linux】安装python依赖库confluent_kafka
  11. 计算机专业计算机二级java有用吗_计算机二级java含金量如何 对就业有帮助吗
  12. 命令提示符死亡之ping教程
  13. 纪念非线性光学诞生:Peter Franken和非线性光学
  14. 【PyTorch实战】用PyTorch实现基于神经网络的图像风格迁移
  15. 3. Zigbee应用程序框架开发指南 - 应用程序框架目录结构
  16. wifi服务器端口映射,主流路由器端口映射的方法
  17. matlab rti dds,[译]*RTI_DDS测试
  18. Puppet erb模板介绍(三十二)
  19. 腾讯云自建k8s对接文件存储CFS
  20. ping不通百度 ubuntu_Ubuntu不可以ping百度,但是可以ping通其ip

热门文章

  1. WebGL、canvas、svg
  2. 关闭数字健康 android 魅族,魅族Flyme数字健康,手机使用情况尽收眼底,还能限制使用...
  3. 2020-2021 ACM-ICPC, Asia Nanjing Regional Contest (XXI Open Cup, Grand Prix of Nanjing)
  4. Android WiFi开发教程(二)——WiFi的搜索和连接
  5. css3做渐变进度条
  6. SplunkEnterprise日志服务程序/SplunkForward通用转发器部署客户端
  7. vrrp协议与keepalived浅析
  8. [题解]Mail.Ru Cup 2018 Round 1 - C. Candies Distribution
  9. day08-代码操作xls文件
  10. 字节跳动如何用7年, 成为腾讯最可怕的对手?