Vue不能观察到数组length的变化

由于 JavaScript 的限制,Vue 不能检测以下变动的数组: 当你利用索引直接设置一个项时,例如:vm.items[indexOfItem] = newValue 当你修改数组的长度时,例如:vm.items.length = newLength

因为vue的响应式是通过 Object.defineProperty 来实现的,但是数组的length属性是不能添加getter和setter,所有无法通过观察length来判断。

为什么Vue不能观察到数组length的变化

如下代码,虽然看起来数组的length是10,但是for in的时候只能遍历出0, 1, 2,导致了只有前三个索引被加上了getter 和setter

var a = [0, 1, 2]
a.length = 10
// 只是显示的给length赋值,索引3-9的对应的value也会赋值undefined
// 但是索引3-9的key都是没有值的
// 我们可以用for-in打印,只会打印0,1,2
for (var key in a) {
 console.log(key) // 0,1,2
}

那么vue提供了一些解决方法

使用内置的Vue.$set

让数组显式的进行某个索引的观察 Vue.set(array, indexOfItem, newValue)

实际上是调用了

Object.defineProperty(array, indexOfItem, {
 enumerable: true,
 configurable: true,
 get() { },
 set(newVal) { }
})

这样可以手动指定需要观察的key,那么就可以达到预期的效果。

重写了 push, pop, shift, unshift, splice, sort, reverse方法

Vue源码

const arrayProto = Array.prototype
export const arrayMethods = Object.create(arrayProto)

/**
 * Intercept mutating methods and emit events
 */
;[
 'push',
 'pop',
 'shift',
 'unshift',
 'splice',
 'sort',
 'reverse'
]
.forEach(function (method) {
 // cache original method
 const original = arrayProto[method]
 def(arrayMethods, method, function mutator (...args) {
  const result = original.apply(this, args)
  const ob = this.__ob__
  let inserted
  switch (method) {
   case 'push':
   case 'unshift':
    inserted = args
    break
   case 'splice':
    inserted = args.slice(2)
    break
  }
  if (inserted) ob.observeArray(inserted)
  // notify change
  ob.dep.notify()
  return result
 })
})

这些是在Array.__proto__上 进行了方法重写或者添加

并且对添加属性的方法如 push,unshift,splice 所添加进来的新属性进行手动观察,源码为

if (inserted) ob.observeArray(inserted)

对以上方法进行了手动的进行消息触发

ob.dep.notify()

结论

vue对数组的length直接改变无法直接进行观察,提供了vue.$set 进行显式观察,并且重写了 push, pop, shift, unshift, splice, sort, reverse方法来进行隐式观察。

以上所述是小编给大家介绍的Vue不能观察到数组length的变化,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对我们网站的支持!

(0)

相关推荐

  • Vue响应式添加、修改数组和对象的值

    有些时候,不得不想添加.修改数组和对象的值,但是直接添加.修改后又失去了getter.setter. 由于 JavaScript 的限制, Vue 不能检测以下变动的数组: 1. 利用索引直接设置一个项时,例如: vm.items[indexOfItem] = newValue 2. 修改数组的长度时,例如: vm.items.length = newLength 为了避免第一种情况,以下两种方式将达到像 vm.items[indexOfItem] = newValue 的效果, 同时也将触发状

  • 详解Vue微信公众号开发踩坑全记录

    本文介绍了Vue微信公众号开发踩坑全记录,分享给大家,也给自己留个笔记. 需求 微信授权登录(基于公众号的登录方案) 接入JS-SDK实现图片上传,分享等功能 现状及难点 采用的Vue框架,前后端分离模式(vue工程仅作为客户端),用户通过域名访问的是客户端,但是微信授权中涉及签名和token校验依赖服务端 JS-SDK需要向服务端获取签名,且获取签名中需要的参数包括所在页面的url,但由于单页应用的路由特殊,其中涉及到IOS和android微信客户端浏览器内核的差异性导致的兼容问题 解决方案

  • 详解vue的数据劫持以及操作数组的坑

    TL;DR 给data添加新属性的时候vm.$set(vm.info,'newKey','newValue') data上面属性值是数组的时候,需要用数组的方法操作数组,而不能通过index或者length属性去操作数组,因为监听不到属性操作的动作. 安装和初使用vue vue是构建用户界面的渐进式框架.所谓的渐进式:vue + components + vue-router + vuex + vue-cli可以根据需要选择相应的功能. 来串命令mkdir vue-apply;cd vue-ap

  • Vue数组更新及过滤排序功能

    前面的话 Vue为了增加列表渲染的功能,增加了一组观察数组的方法,而且可以显示一个数组的过滤或排序的副本.本文将详细介绍Vue数组更新及过滤排序 变异方法 Vue 包含一组观察数组的变异方法,它们将会触发视图更新,包含以下方法 push() 接收任意数量的参数,把它们逐个添加到数组末尾,并返回修改后数组的长度 pop() 从数组末尾移除最后一项,减少数组的length值,然后返回移除的项 shift() 移除数组中的第一个项并返回该项,同时数组的长度减1 unshift() 在数组前端添加任意个

  • 详解vantUI框架在vue项目中的应用踩坑

    1.订单提交地址等组件的应用. 使用的组件有如下: import {Card,button,Toast,AddressList,Popup,AddressEdit,Area} from 'vant' 主要是配货地址编辑这块: <van-address-edit :area-list="areaList" :address-info="addressInfo" show-postal show-delete show-set-default show-searc

  • 浅谈vue的踩坑路

    ------>axios模拟get json一直拿不到文件,先把data放到根目录,再去dev-server.js(就是npm执行的那个文件)里面设置静态资源访问路径app.use('/data',express.static('./data')) ... app.use(hotMiddleware) // serve pure static assets var staticPath = path.posix.join(config.dev.assetsPublicPath, config.d

  • 详解VUE 数组更新

    1.数据方法分类: (1)原数组改变 push  pop  unshift  shift  reverse  sort  splice (2)原数组未变,生成新数组 slice  concat  filter 对于使原数组变化的方法,可以直接更新视图. 对于原数组未变的方法,可以使用新数组替换原来的数组,以使视图发生变化. 示例代码: <!DOCTYPE html> <html lang="zh"> <head> <meta charset=&

  • vue踩坑记录之数组定义和赋值问题

    问题场景:vue页面初始化展示请求后台返回的数据失败,没有报错 <el-form-item label="有效日期"> <div class="block"> <el-date-picker v-model="effective_date" type="daterange" range-separator="至" start-placeholder="开始日期&quo

  • vue 数组和对象不能直接赋值情况和解决方法(推荐)

    Vue 不能检测以下变动的数组: 当你利用索引直接设置一个项时,例如:vm.items[indexOfItem] = newValue 当你修改数组的长度时,例如:vm.items.length = newLength 当第一种情况需求时,可以使用this.$set(this.arr,index,newVal) Vue 不能检测对象属性的添加或删除: 可以使用this.$set(this.person,'age',12) 当需要添加多个对象时,Object.assign({},this.pers

  • Vue.js中数组变动的检测详解

    前言 最近在尝试用Vue.js重构公司的现有业务代码,组件化的设计思路和MVVM的思想让我深深沉迷于其中.但是是踩到了不少坑,就比如这篇文章介绍的数组绑定后的更新检测. 相信大家都知道Observer,Watcher,vm 可谓 Vue 中比较重要的部分,检测数据变动后视图更新的重要环节.在 vue.js中$watch的用法示例 中,我们讨论了如何实现基本的 watch . 接下来,我们来看看如何实现数组变动检测. 例子: // 创建 vm let vm = new Vue({ data: {

随机推荐