关于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 在单页面应用里使用二级套嵌路由
Dec 19 Vue.js
vue中watch的用法汇总
Dec 28 Vue.js
vue前端和Django后端如何查询一定时间段内的数据
Feb 28 Vue.js
vue项目实现分页效果
Mar 24 Vue.js
vue+django实现下载文件的示例
Mar 24 Vue.js
vue使用v-model进行跨组件绑定的基本实现方法
Apr 28 Vue.js
如何使用vue3打造一个物料库
May 08 Vue.js
vue组件的路由高亮问题解决方法
May 11 Vue.js
深入理解Vue的数据响应式
May 15 Vue.js
idea编译器vue缩进报错问题场景分析
Jul 04 Vue.js
详细聊聊vue中组件的props属性
Nov 02 Vue.js
vue router 动态路由清除方式
May 25 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
怎样在UNIX系统下安装php3
2006/10/09 PHP
完善CodeIgniter在IDE中代码提示功能的方法
2014/07/19 PHP
php 数组元素快速去重
2017/05/05 PHP
图片自动缩小 点击放大
2008/07/07 Javascript
javascript innerText和innerHtml应用
2010/01/28 Javascript
jquery清空textarea等输入框实现代码
2013/04/22 Javascript
Jquery使用css方法改变样式实例
2015/05/18 Javascript
js纯数字逐一停止显示效果的实现代码
2016/03/16 Javascript
vue.js初学入门教程(2)
2016/11/07 Javascript
Javascript 对cookie操作详解及实例
2016/12/29 Javascript
微信小程序动态添加分享数据
2017/06/14 Javascript
vue实现全选和反选功能
2017/08/31 Javascript
JavaScript实现三级级联特效
2017/11/05 Javascript
微信小程序模拟cookie的实现
2018/06/20 Javascript
vue组件库的在线主题编辑器的实现思路
2020/04/03 Javascript
Windows下用py2exe将Python程序打包成exe程序的教程
2015/04/08 Python
Python文件右键找不到IDLE打开项解决办法
2015/06/08 Python
举例讲解Python中的迭代器、生成器与列表解析用法
2016/03/20 Python
python根据list重命名文件夹里的所有文件实例
2018/10/25 Python
pygame游戏之旅 按钮上添加文字的方法
2018/11/21 Python
基于Tensorflow一维卷积用法详解
2020/05/22 Python
如何用PyPy让你的Python代码运行得更快
2020/12/02 Python
利用CSS3的checked伪类实现OL的隐藏显示的方法
2010/12/18 HTML / CSS
彪马香港官方网上商店:PUMA香港
2020/12/06 全球购物
.NET笔试题(20个问题)
2016/02/02 面试题
爱情检讨书大全
2014/01/21 职场文书
社会治安综合治理管理责任书
2014/04/16 职场文书
基层党员公开承诺书
2014/05/29 职场文书
小学开学标语
2014/07/01 职场文书
党的生日活动方案
2014/08/15 职场文书
教师反腐倡廉演讲稿
2014/09/03 职场文书
给医院的感谢信
2015/01/21 职场文书
个人原因辞职信模板
2015/05/13 职场文书
现实表现证明材料
2015/06/19 职场文书
2019年七夕情人节浪漫祝福语大全!
2019/08/08 职场文书
mysql分表之后如何平滑上线详解
2021/11/01 MySQL