关于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 的 v-model用法实例
Nov 23 Vue.js
Vue项目如何引入bootstrap、elementUI、echarts
Nov 26 Vue.js
vue祖孙组件之间的数据传递案例
Dec 07 Vue.js
如何使用RoughViz可视化Vue.js中的草绘图表
Jan 30 Vue.js
vue3.0 自适应不同分辨率电脑的操作
Feb 06 Vue.js
如何管理Vue中的缓存页面
Feb 06 Vue.js
vue中三级导航的菜单权限控制
Mar 31 Vue.js
关于vue中如何监听数组变化
Apr 28 Vue.js
使用Vue3+Vant组件实现App搜索历史记录功能(示例代码)
Jun 09 Vue.js
Vue.js中v-bind指令的用法介绍
Mar 13 Vue.js
vue2的 router在使用过程中遇到的一些问题
Apr 13 Vue.js
Vue router配置与使用分析讲解
Dec 24 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结束标签的使用细节探讨及联想
2013/03/04 PHP
如何使用php等比例缩放图片
2016/10/12 PHP
Laravel框架实现修改登录和注册接口数据返回格式的方法
2018/08/17 PHP
学习YUI.Ext 第六天--关于树TreePanel(Part 1)
2007/03/10 Javascript
javascript实现的listview效果
2007/04/28 Javascript
使用JS进行目录上传(相当于批量上传)
2010/12/05 Javascript
关于图片按比例自适应缩放的js代码
2011/10/30 Javascript
js移除事件 js绑定事件实例应用
2012/11/28 Javascript
javascript复制粘贴与clipboardData的使用
2014/10/16 Javascript
js实现带农历和八字等信息的日历特效
2016/05/16 Javascript
微信小程序 保留小数(toFixed)详细介绍
2016/11/16 Javascript
JS实现动态添加DOM节点和事件的方法示例
2017/04/28 Javascript
利用babel将es6语法转es5的简单示例
2017/12/01 Javascript
vue-cli history模式实现tomcat部署报404的解决方式
2019/09/06 Javascript
JavaScript 作用域实例分析
2019/10/02 Javascript
Vue.js自定义指令学习使用详解
2019/10/19 Javascript
vue实现页面内容禁止选中功能,仅输入框和文本域可选
2019/11/09 Javascript
vue-父子组件和ref实例详解
2019/11/10 Javascript
JavaScript实现省市联动效果
2019/11/22 Javascript
[01:11:21]DOTA2-DPC中国联赛 正赛 VG vs Elephant BO3 第一场 3月6日
2021/03/11 DOTA
Python命名空间详解
2014/08/18 Python
利用Python实现颜色色值转换的小工具
2016/10/27 Python
django上传图片并生成缩略图方法示例
2017/12/11 Python
详谈python在windows中的文件路径问题
2018/04/28 Python
对python pandas 画移动平均线的方法详解
2018/11/28 Python
Python开发之Nginx+uWSGI+virtualenv多项目部署教程
2019/05/13 Python
python数据抓取3种方法总结
2021/02/07 Python
建议书的格式
2014/05/12 职场文书
学校宣传标语
2014/06/18 职场文书
审计班子对照检查材料
2014/08/27 职场文书
运动会加油稿30字
2015/07/21 职场文书
2016十一国庆节感言
2015/12/09 职场文书
阳光体育运动标语口号
2015/12/26 职场文书
PHP命令行与定时任务
2021/04/01 PHP
left join、inner join、right join的区别
2021/04/05 MySQL
深度学习小工程练习之垃圾分类详解
2021/04/14 Python