关于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 相关文章推荐
vue3.0+vue-router+element-plus初实践
Dec 02 Vue.js
Vue实现小购物车功能
Dec 21 Vue.js
vue 实现图片懒加载功能
Dec 31 Vue.js
vue3自定义dialog、modal组件的方法
Jan 04 Vue.js
如何使用RoughViz可视化Vue.js中的草绘图表
Jan 30 Vue.js
手动实现vue2.0的双向数据绑定原理详解
Feb 06 Vue.js
详解Vue的七种传值方式
Feb 08 Vue.js
vue实现同时设置多个倒计时
May 20 Vue.js
Vue实现tab导航栏并支持左右滑动功能
Jun 28 Vue.js
vue实现Toast组件轻提示
Apr 10 Vue.js
vue代码分块和懒加载非必要资源文件
Apr 11 Vue.js
vue使用watch监听属性变化
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
介绍一些PHP判断变量的函数
2012/04/24 PHP
php json_encode值中大括号与花括号区别
2013/09/30 PHP
php基于双向循环队列实现历史记录的前进后退等功能
2015/08/08 PHP
解析PHP的Yii框架中cookie和session功能的相关操作
2016/03/17 PHP
Yii2.0中的COOKIE和SESSION用法
2016/08/12 PHP
php检测mysql表是否存在的方法小结
2017/07/20 PHP
javascript中的location用法简单介绍
2007/03/07 Javascript
js日期、星座的级联显示代码
2014/01/23 Javascript
用js一次改变多个input的readonly属性值的方法
2014/06/11 Javascript
js实现简易的单数字随机抽奖(0-9)
2020/03/19 Javascript
JS实现左右拖动改变内容显示区域大小的方法
2015/10/13 Javascript
JS实现的数字格式化功能示例
2017/02/10 Javascript
JS对象创建的几种方式整理
2017/02/28 Javascript
vue主动刷新页面及列表数据删除后的刷新实例
2018/09/16 Javascript
vue 实现边输入边搜索功能的实例讲解
2018/09/16 Javascript
bootstrap table实现iview固定列的效果实例代码详解
2019/09/30 Javascript
vue 添加和编辑用同一个表单,el-form表单提交后清空表单数据操作
2020/08/03 Javascript
Python2.x版本中cmp()方法的使用教程
2015/05/14 Python
python 实现登录网页的操作方法
2018/05/11 Python
Django中ajax发送post请求 报403错误CSRF验证失败解决方案
2019/08/13 Python
通过实例了解python__slots__使用方法
2020/09/14 Python
美国最大最全的亚洲购物网站:美国亚米网(Yamibuy)
2020/05/05 全球购物
UML设计模式笔试题
2014/06/07 面试题
函授毕业生的自我鉴定
2013/11/26 职场文书
企业总经理岗位职责
2014/02/13 职场文书
人事科岗位职责范本
2014/03/02 职场文书
环保倡议书300字
2014/05/15 职场文书
班训口号大全
2014/06/18 职场文书
党支部创先争优承诺书
2014/08/30 职场文书
优秀团员事迹材料
2014/12/25 职场文书
初中家长评语和期望
2014/12/26 职场文书
毕业论文指导教师评语
2014/12/30 职场文书
30岁前绝不能错过的10本书
2019/08/08 职场文书
CSS布局之浮动(float)和定位(position)属性的区别
2021/09/25 HTML / CSS
使用python创建股票的时间序列可视化分析
2022/03/03 Python
动画《朋友游戏》公开佐藤友生绘制的开播纪念绘
2022/04/06 日漫