关于vue中如何监听数组变化


Posted in Vue.js onApril 28, 2021

前言

前段时间学习了关于vue中响应式数据的原理,(并作了学习笔记vue响应式原理),其实是通过Object.defineProperty控制getter和setter,并利用观察者模式完成的响应式设计。那么数组有一系列的操作方法,这些方法并不会触发数组的getter和setter方法。那么vue中针对数组的响应式设计是如何实现的呢...那么我们一起去学习下吧~

源码部分

https://github.com/vuejs/vue/blob/dev/src/core/observer/array.js

从哪开始第一步学习呢

Emmmm...
我觉得要先把Vue中的数据响应式原理弄清楚,这样对于理解vue中是如何检测数组的变化才比较好,所以,可以去网上找下文章然后配合源码进行阅读,相信你一定会理解的。推荐下我之前看的一篇博客,还有我看过后自己写的学习记录吧,哈哈。

vue响应式原理

vue的双向绑定原理和实现

好的,先看看这个吧。哈哈!

从图开始

咱们先看下下面的图,先了解下vue中实现的思路,这样接下来再看源码的实现,会一清二楚,明明白白。

关于vue中如何监听数组变化

看到这个图然后思考一下,是不是大致了解了~

首先判断浏览器是否支持__proto__指针

重写数组的这7个方法,然后根据是否支持__proto__,将改写后的数组指向数组的prototype。

是不是很简单!!!

看看源码吧

了解了实现原理,那么我们再看看源码吧,看下源码主要是更深入的了解作者是如何实现的,也可以看下优秀的代码编码方式,加以学习。

关于一些解释我就写在下面的代码块中了哈!

//https://github.com/vuejs/vue/blob/dev/src/core/observer/array.js


//def方法是基于Object.defineProperty封装的一层方法,很简单,我会在下面把代码贴出来,免得大家去找了。
import { def } from '../util/index' 

//保存下原生的数组原型对象
const arrayProto = Array.prototype

//进行原型连接,将arrayMethods的原型指向Array.prototype
export const arrayMethods = Object.create(arrayProto)

const methodsToPatch = [
  'push',
  'pop',
  'shift',
  'unshift',
  'splice',
  'sort',
  'reverse'
]

methodsToPatch.forEach(function (method) {
  // 缓存原生的方法
  const original = arrayProto[method]
  def(arrayMethods, method, function mutator (...args) {
    var args = [], 
    len = arguments.length;
    while (len--) args[len] = arguments[len];
    const result = original.apply(this, args) // 原来的数组方法执行结果
    const ob = this.__ob__ // 这个__ob__就是Observe的实例~~~~
    let inserted
    switch (method) {
      case 'push':
      case 'unshift':
        inserted = args
        break
      case 'splice':
        inserted = args.slice(2)
        break
    }
    if (inserted) ob.observeArray(inserted) // 如果数组有变化,则重新调用observeArray
    // notify change
    ob.dep.notify()  //
    return result
  })
})

这个是关于Observe的代码:

var Observer = function Observer(value) {
    this.value = value;
    this.dep = new Dep();
    this.vmCount = 0;
    def(value, '__ob__', this);  //这里会看到在每个对象数据上都会绑定一个Observe的实例,所以上面代码中的this.__ob__就是这个
    if (Array.isArray(value)) { // 这里判断是否是数组类型的数据,如果是的话就走observeArray
      if (hasProto) {
        protoAugment(value, arrayMethods);
      } else {
        copyAugment(value, arrayMethods, arrayKeys);
      }
      this.observeArray(value); //这里就是处理数组类型的数据,如下
    } else {
      this.walk(value);
    }
  };

如下是observeArray的实现:

Observer.prototype.observeArray = function observeArray(items) {
    for (var i = 0, l = items.length; i < l; i++) {
      observe(items[i]); // 这个observe方法如下
    }
  };

在这里我们看下observe这个方法:

function observe(value, asRootData) {
    if (!isObject(value) || value instanceof VNode) {
      return
    }
    var ob;
    if (hasOwn(value, '__ob__') && value.__ob__ instanceof Observer) {
      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
  }

这个是关于def方法的实现,很简单我就不说了哈:

function def (obj, key, val, enumerable) {
    Object.defineProperty(obj, key, {
      value: val,
      enumerable: !!enumerable,
      writable: true,
      configurable: true
    });
}

以上就是关于vue中如何监听数组变化的详细内容,更多关于vue如何监听数组的资料请关注三水点靠木其它相关文章!

Vue.js 相关文章推荐
vue单元格多列合并的实现
Nov 26 Vue.js
对vue生命周期的深入理解
Dec 03 Vue.js
vue中如何自定义右键菜单详解
Dec 08 Vue.js
Vue 集成 PDF.js 实现 PDF 预览和添加水印的步骤
Jan 22 Vue.js
Vue项目打包部署到apache服务器的方法步骤
Feb 01 Vue.js
vue使用echarts画组织结构图
Feb 06 Vue.js
vue中h5端打开app(判断是安卓还是苹果)
Feb 26 Vue.js
vue backtop组件的实现完整代码
Apr 07 Vue.js
解决Vue+SpringBoot+Shiro跨域问题
Jun 09 Vue.js
SSM VUE Axios详解
Oct 05 Vue.js
vue ref如何获取子组件属性值
Mar 31 Vue.js
解决vue自定义组件@click点击失效问题
Apr 30 Vue.js
vue实现简单数据双向绑定
Apr 28 #Vue.js
vue引入Excel表格插件的方法
Apr 28 #Vue.js
原生JS封装vue Tab切换效果
vue项目两种方式实现竖向表格的思路分析
vue首次渲染全过程
浅谈vue2的$refs在vue3组合式API中的替代方法
Vue.js 带下拉选项的输入框(Textbox with Dropdown)组件
You might like
对javascript和select部件的结合运用
2006/10/09 PHP
制作个性化的WordPress登陆界面的实例教程
2016/05/21 PHP
Yii统计不同类型邮箱数量的方法
2016/10/18 PHP
浅谈PHP各环境下的伪静态配置
2019/03/13 PHP
laravel实现上传图片,并且制作缩略图,按照日期存放的代码
2019/10/16 PHP
JS实现浏览器菜单命令
2006/09/05 Javascript
扩展String功能方法
2006/09/22 Javascript
javaScript 利用闭包模拟对象的私有属性
2011/12/29 Javascript
使用JavaScript修改浏览器URL地址栏的实现代码
2013/10/21 Javascript
nodejs实现遍历文件夹并统计文件大小
2015/05/28 NodeJs
初识angular框架后的所思所想
2016/02/19 Javascript
JQuery中attr属性和jQuery.data()学习笔记【必看】
2016/05/18 Javascript
jQuery插件passwordStrength密码强度指标详解
2016/06/24 Javascript
jQuery模仿京东/天猫商品左侧分类导航菜单效果
2016/06/29 Javascript
javascript实现复选框全选或反选
2017/02/04 Javascript
jquery PrintArea 实现票据的套打功能(代码)
2017/03/17 Javascript
JS中touchstart事件与click事件冲突的解决方法
2018/03/12 Javascript
浅谈Redux中间件的实践
2018/07/27 Javascript
setTimeout与setInterval的区别浅析
2019/03/23 Javascript
js canvas实现5张图片合成一张图片
2019/07/15 Javascript
详解Django中的ifequal和ifnotequal标签使用
2015/07/16 Python
简单解析Django框架中的表单验证
2015/07/17 Python
python中函数传参详解
2016/07/03 Python
Python制作刷网页流量工具
2017/04/23 Python
详解python单元测试框架unittest
2018/07/02 Python
Python机器学习算法库scikit-learn学习之决策树实现方法详解
2019/07/04 Python
Python要如何实现列表排序的几种方法
2020/02/21 Python
护士自荐信
2013/10/25 职场文书
事务机电主管工作职责
2014/02/25 职场文书
师范生自我鉴定
2014/03/20 职场文书
小学教师寄语大全
2014/04/03 职场文书
廉洁教育学习材料
2014/05/19 职场文书
党员学习新党章思想汇报
2014/10/25 职场文书
python爬虫selenium模块详解
2021/03/30 Python
Java 常见的限流算法详细分析并实现
2022/04/07 Java/Android
SpringBoot Http远程调用的方法
2022/08/14 Java/Android