精华内容
下载资源
问答
  • vue如何监听数组变化

    千次阅读 2020-05-09 23:54:22
    Vue.js观察数组变化主要通过以下7个方法(push、pop、shift、unshift、splice、sort、reverse) 怎么实现? 通过对data数据中数组的这7个方法进行重新包装(注意只是data数据中的数组) 为什么不直接对Array....
    Vue.js观察数组变化主要通过以下7个方法(push、pop、shift、unshift、splice、sort、reverse)

    怎么实现?

    通过对data数据中数组的这7个方法进行重新包装(注意只是data数据中的数组)

    为什么不直接对Array.prototype的原型方法进行重新包装?

    因为不应该过多地去影响全局

    案例:

    const patchArray = (function () {
        const methodsToPatch = [
            'push',
            'pop',
            'shift',
            'unshift',
            'splice',
            'reverse',
            'sort'
        ];
    
    //设置对象属性的工具方法
        function def (obj, key, val) {
            Object.defineProperty(obj, key, {
                value: val,
                enumerable: true,
                writable: true,
                configurable: true
            });
        }
    
        const arrayProto = Array.prototype, //缓存Array的原型
            arrayMethods = Object.create(arrayProto); //继承Array的原型
    
        methodsToPatch.forEach(function (method, index) {
            def(arrayMethods, method, function (...args) {
                //首先调用Array原型的方法
                const res = arrayProto[method].apply(this, args);
                //data中每个数组都有一个__ob__的私有属性指向创建的Observer实例(有兴趣看看源码中的observe方法,这里不详述)
                const ob = this.__ob__;
    
                let inserted = null;
    
                //记录插入的值
                switch(method) {
                    case 'push':
                    case 'unshift':
                        inserted = args;
                        break;
                    case 'splice':
                        inserted = args.slice(2);
                        break;
                }
    
                if (inserted) {
                    //如果是调用了push、unshift、splice,则尝试对新插入的值进行响应式绑定,因为插入的值有可能是对象(Object)或者数组(Array)
                    ob && ob.observeArray(inserted);
                }
    
                console.log('数组发生改变了');
    
                //向所有依赖发送通知,告诉它们数组的值发生变化了
                ob && ob.dep.notify();
                return res;
            });
        });
    
        return function (target) {
            //看看浏览器支不支持__proto__这个属性,通过改变__proto__的值,可以设置对象的原型
            if ('__proto__' in {}) {
                //将数组的原型指向arrayMethods,这样当数组调用上述的7个方法时,其实是调用arrayMethods中的方法而不是调用Array.prototype中的方法
                target.__proto__ = arrayMethods;
            } else {
                //如果浏览器不支持__proto__,则设置数组对应的属性,这样当数组调用上述的7个方法时,其实是调用数组对应属性指向的方法
                for (let i = 0, l = methodsToPatch.length; i < l; i++) {
                    let key = methodsToPatch[i];
                    def(target, key, arrayMethods[key]);
                }
            }
        }
    })();
    
    //测试
    let arr = [1, 2, 3];
    patchArray(arr);
    arr.push(4);
    
    展开全文
  • Vue如何监听数组变化

    千次阅读 2021-02-21 09:43:27
    文章目录Vue如何监听数组变化Vue为什么不能检测数组变动$set为啥能检测数组变动 Vue如何监听数组变化? 理解: 使用函数劫持的方式,重写了数组的方法 Vue 将 data 中的数组,进行了原型链重写。指向了自己...
     故心故心故心故心小故冲啊 
    

    提示:写完文章后,目录可以自动生成,如何生成可参考右边的帮助文档


    Vue如何监听数组的变化?

    理解:
    使用函数劫持的方式,重写了数组的方法 Vue 将 data 中的数组,进行了原型链重写。指向了自己定义的数组原型方法,这样当调用数组 api 时,可以通知依赖更新.如果数组中包含着引用类型。会对数组中的引用类型再次进行监控

    重写了数组中的原型的方法
    在这里插入图片描述

    1.获取数组中的原型方法,因为拦截后还需要这些原生的方法帮助我们实现数组的变化
    2.对这些原型的方法使用object.deinePropetry进行拦截操作(def方法)
    3.把拦截的数组的原型指向改造后的原型

    原理:
    在这里插入图片描述

    Vue为什么不能检测数组变动

    性能问题而没有采用这种方式监听数组。
    性能代价和获得的用户收益不成正比
    在这里插入图片描述

    通过源码我们可以知道,Vue 没有对数组每个键设置响应式的过程,而是直接对值进行递归设置响应式。

    $set为啥能检测数组变动

    这就是vue重写数组方法的原因,利用数组这些方法触发使得每一项的value都是响应式的

    展开全文
  • vue-监听数组变化

    2018-03-13 21:10:00
    Vue.js观察数组变化主要通过以下7个方法(push、pop、shift、unshift、splice、sort、reverse) 怎么实现? 通过对data数据中数组的这7个方法进行重新包装(注意只是data数据中的数组) 为什么不直接对Array....

    Vue.js观察数组变化主要通过以下7个方法(push、pop、shift、unshift、splice、sort、reverse)

    怎么实现?

    通过对data数据中数组的这7个方法进行重新包装(注意只是data数据中的数组)

    为什么不直接对Array.prototype的原型方法进行重新包装?

    因为不应该过多地去影响全局

    代码实现

     1 const patchArray = (function () {
     2     const methodsToPatch = [
     3         'push',
     4         'pop',
     5         'shift',
     6         'unshift',
     7         'splice',
     8         'reverse',
     9         'sort'
    10     ];
    11 
    12 //设置对象属性的工具方法
    13     function def (obj, key, val) {
    14         Object.defineProperty(obj, key, {
    15             value: val,
    16             enumerable: true,
    17             writable: true,
    18             configurable: true
    19         });
    20     }
    21 
    22     const arrayProto = Array.prototype, //缓存Array的原型
    23         arrayMethods = Object.create(arrayProto); //继承Array的原型
    24 
    25     methodsToPatch.forEach(function (method, index) {
    26         def(arrayMethods, method, function (...args) {
    27             //首先调用Array原型的方法
    28             const res = arrayProto[method].apply(this, args);
    29             //data中每个数组都有一个__ob__的私有属性指向创建的Observer实例(有兴趣看看源码中的observe方法,这里不详述)
    30             const ob = this.__ob__;
    31 
    32             let inserted = null;
    33 
    34             //记录插入的值
    35             switch(method) {
    36                 case 'push':
    37                 case 'unshift':
    38                     inserted = args;
    39                     break;
    40                 case 'splice':
    41                     inserted = args.slice(2);
    42                     break;
    43             }
    44 
    45             if (inserted) {
    46                 //如果是调用了push、unshift、splice,则尝试对新插入的值进行响应式绑定,因为插入的值有可能是对象(Object)或者数组(Array)
    47                 ob && ob.observeArray(inserted);
    48             }
    49 
    50             console.log('数组发生改变了');
    51 
    52             //向所有依赖发送通知,告诉它们数组的值发生变化了
    53             ob && ob.dep.notify();
    54             return res;
    55         });
    56     });
    57 
    58     return function (target) {
    59         //看看浏览器支不支持__proto__这个属性,通过改变__proto__的值,可以设置对象的原型
    60         if ('__proto__' in {}) {
    61             //将数组的原型指向arrayMethods,这样当数组调用上述的7个方法时,其实是调用arrayMethods中的方法而不是调用Array.prototype中的方法
    62             target.__proto__ = arrayMethods;
    63         } else {
    64             //如果浏览器不支持__proto__,则设置数组对应的属性,这样当数组调用上述的7个方法时,其实是调用数组对应属性指向的方法
    65             for (let i = 0, l = methodsToPatch.length; i < l; i++) {
    66                 let key = methodsToPatch[i];
    67                 def(target, key, arrayMethods[key]);
    68             }
    69         }
    70     }
    71 })();
    72 
    73 //测试
    74 let arr = [1, 2, 3];
    75 patchArray(arr);
    76 arr.push(4);

     

    转载于:https://www.cnblogs.com/haiying-zheng/p/8562199.html

    展开全文
  • 主要为大家详细解析了Vue监听数组变化的源码,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
  • Vue 如何监听数组变化 我们知道通过Object.defineProperty()劫持数组为其设置getter和setter后,调用的数组的push、splice、pop等方法改变数组元素时并不会触发数组的setter,这就会造成使用上述方法改变数组后,...

    Vue 如何监听数组的变化

    我们知道通过Object.defineProperty()劫持数组为其设置getter和setter后,调用的数组的push、splice、pop等方法改变数组元素时并不会触发数组的setter,这就会造成使用上述方法改变数组后,页面上并不能及时体现这些变化,也就是数组数据变化不是响应式的(对上述不了解的可以参考这篇文章)。但实际用vue开发时,对于响应式数组,使用push、splice、pop等方法改变数组时,页面会及时体现这种变化,那么vue中是如何实现的呢?

    通过vue源码可以看出,vue重写了数组的push、splice、pop等方法。

    
     1 // src/core/observer/array.js
     2 
     3 // 获取数组的原型Array.prototype,上面有我们常用的数组方法
     4 const arrayProto = Array.prototype
     5 // 创建一个空对象arrayMethods,并将arrayMethods的原型指向Array.prototype
     6 export const arrayMethods = Object.create(arrayProto)
     7 
     8 // 列出需要重写的数组方法名
     9 const methodsToPatch = [
    10   'push',
    11   'pop',
    12   'shift',
    13   'unshift',
    14   'splice',
    15   'sort',
    16   'reverse'
    17 ]
    18 // 遍历上述数组方法名,依次将上述重写后的数组方法添加到arrayMethods对象上
    19 methodsToPatch.forEach(function (method) {
    20   // 保存一份当前的方法名对应的数组原始方法
    21   const original = arrayProto[method]
    22   // 将重写后的方法定义到arrayMethods对象上,function mutator() {}就是重写后的方法
    23   def(arrayMethods, method, function mutator (...args) {
    24     // 调用数组原始方法,并传入参数args,并将执行结果赋给result
    25     const result = original.apply(this, args)
    26     // 当数组调用重写后的方法时,this指向该数组,当该数组为响应式时,就可以获取到其__ob__属性
    27     const ob = this.__ob__
    28     let inserted
    29     switch (method) {
    30       case 'push':
    31       case 'unshift':
    32         inserted = args
    33         break
    34       case 'splice':
    35         inserted = args.slice(2)
    36         break
    37     }
    38     if (inserted) ob.observeArray(inserted)
    39     // 将当前数组的变更通知给其订阅者
    40     ob.dep.notify()
    41     // 最后返回执行结果result
    42     return result
    43   })
    44 })

    从上面可以看出array.js中重写了数组的push、pop、shift、unshift、splice、sort、reverse七种方法,重写方法在实现时除了将数组方法名对应的原始方法调用一遍并将执行结果返回外,还通过执行ob.dep.notify()将当前数组的变更通知给其订阅者,这样当使用重写后方法改变数组后,数组订阅者会将这边变化更新到页面中。

    重写完数组的上述7种方法外,我们还需要将这些重写的方法应用到数组上,因此在Observer构造函数中,可以看到在监听数据时会判断数据类型是否为数组。当为数组时,如果浏览器支持__proto__,则直接将当前数据的原型__proto__指向重写后的数组方法对象arrayMethods,如果浏览器不支持__proto__,则直接将arrayMethods上重写的方法直接定义到当前数据对象上;当数据类型为非数组时,继续递归执行数据的监听。

    / src/core/observer/index.js
     2 export class Observer {
     3   ...
     4   constructor (value: any) {
     5     this.value = value
     6     this.dep = new Dep()
     7     this.vmCount = 0
     8     def(value, '__ob__', this)
     9     if (Array.isArray(value)) {
    10       if (hasProto) {
    11         protoAugment(value, arrayMethods)
    12       } else {
    13         copyAugment(value, arrayMethods, arrayKeys)
    14       }
    15       this.observeArray(value)
    16     } else {
    17       this.walk(value)
    18     }
    19   }
    20   ...
    21 }
    22 function protoAugment (target, src: Object) {
    23   /* eslint-disable no-proto */
    24   target.__proto__ = src
    25   /* eslint-enable no-proto */
    26 }
    27 function copyAugment (target: Object, src: Object, keys: Array<string>) {
    28   for (let i = 0, l = keys.length; i < l; i++) {
    29     const key = keys[i]
    30     def(target, key, src[key])
    31   }
    32 }

    经过上述处理后,对于数组,当我们调用其方法处理数组时会按照如下原型链来获取数组方法:

    对于响应式数组,当浏览器支持__proto__属性时,使用push等方法时先从其原型arrayMethods上寻找push方法,也就是重写后的方法,处理之后数组的变化会通知到其订阅者,更新页面,当在arrayMethods上查询不到时会向上在Array.prototype上查询;当浏览器不支持__proto__属性时,使用push等方法时会先从数组自身上查询,如果查询不到会向上再Array.prototype上查询。

    对于非响应式数组,当使用push等方法时会直接从Array.prototype上查询。

    值得一提的是源码中通过判断浏览器是否支持__proto__来分别使用protoAugment和copyAugment 方法将重写后的数组方法应用到数组中,这是因为对于IE10及以下的IE浏览器是不支持__proto__属性的:

    上述截图参考于Vue源码解析五——数据响应系统

    结论:

    在将数组处理成响应式数据后,如果使用数组原始方法改变数组时,数组值会发生变化,但是并不会触发数组的setter来通知所有依赖该数组的地方进行更新,为此,vue通过重写数组的某些方法来监听数组变化,重写后的方法中会手动触发通知该数组的所有依赖进行更新。

    如果我的内容能对你有所帮助,我就很开心啦!

    展开全文
  • vue怎么监听数组和对象的变化

    千次阅读 2020-06-16 17:22:24
    但是数组和对象的变化很多小白可能不太会,接下来我就为大家展示怎么监听数组和对象 废话不多说。上代码 data() { return { arr: ["sss", "scsdr", 22], obj: { a: "bai", b: 2 } }; }, data中有一个数组...
  • vue 监听数组变化

    2017-06-23 15:06:00
    由于js的限制,vue无法进行监听数组; 由于 JavaScript 的限制, Vue 不能检测以下变动的数组: 当你利用索引直接设置一个项时,例如:vm.items[indexOfItem] = newValue 当你修改数组的长度时,例如:vm.items....
  • vue中是如何监听数组变化

    万次阅读 多人点赞 2019-08-22 11:26:21
    vue中是如何监听数组变化? 参考于Vue源码解析五——数据响应系统 参考文献: [1] 如何监听数组变化?
  • Vue监听数组长度变化

    千次阅读 2019-02-20 15:36:32
    Vue监听数组长度变化: 最近APP项目需要监听数组长度的变化,界面上做出相应变化;百度了很多,未果,请教了同事,了解到一个方法,特来分享一下。 watch: { 'list.length': { handler(newValue, oldValue) { ...
  • VUE-解决无法监听数组、对象的变化

    千次阅读 2019-03-03 13:27:25
    一、vue监听数组的变化: 1、vue能够监听数组变化的场景 【1】通过赋值的形式改变正在被监听的数组; 【2】通过splice(index,num,val)的形式改变正在被监听的数组; 【3】通过数组的push的形式改变正在被监听的...
  • vue的数据绑定用Object.defineProperty的getter和setter对一个对象属性的变化进行监听,并且通过依赖关系作出相应的视图更新。但由于js的限制,vue无法检测到以下数组的变动:...如何监听数组变化? vue中是如何监听数.
  • vue2.0监听数组中对象属性的变化

    万次阅读 2017-11-29 11:17:49
    vue项目中如何对数组中的对象属性变化进行监听呢? data () { return { aDemo: [ { key1: '', key2: '' } ] } }, watch: { aDemo:{ handler: function (newVal) {
  • 重新定义数组原型 创建新对象,原型指向oldArrPrototype const oldArrPrototype=Array.prototype; const ArrProto=Object.create(oldArrPrototype); ['push','pop','shift','unshift'].forEach(methodName=>{ ...
  • 但实际用vue开发时,对于响应式数组,使用push、splice、pop等方法改变数组时,页面会及时体现这种变化,那么vue中是如何实现的呢? 通过vue源码可以看出,vue重写了数组的push、splice、pop等方法。 // src/core/...
  • vue监听数组内部元素

    千次阅读 2019-08-07 14:04:24
    VUE中,对数组监听是浅监听,也就是它只能监听数组的长度或者有无的变化,当我们修改数组中的某一个值时,也就是数组的长度状态并没有改变时,在正常情况下它是无法监听到的,在watch中我们知道可以使用deep...
  • 由于 JavaScript 的限制,Vue 不能检测以下数组的变动: 1.当你利用索引直接设置一个数组项时,例如:vm.items[indexOfItem] = newValue 2.当你修改数组的长度时,例如:vm.items.length = newLength 举个例子: var...
  • Vue监听数组 watch监听

    千次阅读 2020-10-05 15:48:53
    Vue监听数组解析 1,简单监听一个参数,demo如下 data() { return { msg: "test---test", } }, watch: { msg(newVal, oldVal) { console.log(newVal) console.log(oldVal) }, }, created() { thi
  • vue】watch监听数组变化

    千次阅读 2019-04-07 23:26:00
    watch: {  list: {  deep: true,//深度监听  handler: function() {  dosomething  }  } }, 转载于:https://www.cnblogs.com/kevinmajesty/p/10668066.html...
  • vue监听数组、对象变化

    千次阅读 2020-03-27 22:20:38
    1.vue单独监听一个数组或者一个对象变化 watch:{ 'payList' : { handler : function(newVal,oldVal){ console.log(newVal,'变化后的值',oldVal,‘变化前的值’) } } } 2.如果你想监听一个数组中多个对象是否...
  • 我们知道通过Object.defineProperty()劫持数组为...但实际用vue开发时,对于响应式数组,使用push、splice、pop等方法改变数组时,页面会及时体现这种变化,那么vue中是如何实现的呢? 答案是 vue 重写了数组的push、s
  • vue2中无法监听数组变化 通过数组索引改变数组元素的值 改变数组的长度 对象 vue2中可以监听对象变化 通过对象.属性名修改对象的值 vue2中无法监听对象变化 通过对象.属性名添加对象的值

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 19,137
精华内容 7,654
关键字:

vue无法监听数组的变化

vue 订阅