关于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 18 Vue.js
Vue3+elementui plus创建项目的方法
Dec 01 Vue.js
vue3.0实现插件封装
Dec 14 Vue.js
vue 实现图片懒加载功能
Dec 31 Vue.js
基于Vue2实现移动端图片上传、压缩、拖拽排序、拖拽删除功能
Jan 05 Vue.js
vue 递归组件的简单使用示例
Jan 14 Vue.js
如何使用vue3打造一个物料库
May 08 Vue.js
深入理解Vue的数据响应式
May 15 Vue.js
详解Vue的sync修饰符
May 15 Vue.js
vue+iview实现手机号分段输入框
Mar 25 Vue.js
VUE使用draggable实现组件拖拽
Apr 06 Vue.js
vue3使用vuedraggable实现拖拽功能
Apr 06 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
优化WordPress的Google字体以加速国内服务器上的运行
2015/11/24 PHP
针对多用户实现头像上传功能PHP代码 适用于登陆页面制作
2016/08/17 PHP
PHP搭建大文件切割分块上传功能示例
2017/01/04 PHP
动感效果的TAB选项卡jquery 插件
2011/07/09 Javascript
button没写type=button会导致点击时提交
2014/03/06 Javascript
javascript学习笔记(二)数组和对象部分
2014/09/30 Javascript
jQuery实现提交按钮点击后变成正在处理字样并禁止点击的方法
2015/03/24 Javascript
JavaScript获取网页表单action属性的方法
2015/04/02 Javascript
jQuery 移动端artEditor富文本编辑器
2016/01/11 Javascript
PHP抓取HTTPS内容和错误处理的方法
2016/09/30 Javascript
小程序登录态管理的方法示例
2018/11/13 Javascript
vue返回上一页面时回到原先滚动的位置的方法
2018/12/20 Javascript
js脚本中执行java后台代码方法解析
2019/10/11 Javascript
javascript json对象小技巧之键名作为变量用法分析
2019/11/11 Javascript
Python中for循环详解
2014/01/17 Python
跟老齐学Python之有容乃大的list(2)
2014/09/15 Python
Python标准库之多进程(multiprocessing包)介绍
2014/11/25 Python
Python的Flask框架中实现登录用户的个人资料和头像的教程
2015/04/20 Python
Python函数式编程指南(三):迭代器详解
2015/06/24 Python
Python之list对应元素求和的方法
2018/06/28 Python
python+selenium+chromedriver实现爬虫示例代码
2020/04/10 Python
matlab 计算灰度图像的一阶矩,二阶矩,三阶矩实例
2020/04/22 Python
纯CSS3实现地球自转实现代码(图文教程附送源码)
2012/12/26 HTML / CSS
HTML5无刷新改变当前url的代码
2017/03/15 HTML / CSS
阿迪达斯德国官方网站:adidas德国
2017/07/12 全球购物
英国创新设计文具、卡片和礼品包装网站:Paperchase
2018/07/14 全球购物
在什么时候需要使用"常引用"
2015/12/31 面试题
给老师的检讨书
2014/02/11 职场文书
交通事故协议书
2014/04/15 职场文书
学校领导班子对照检查材料
2014/09/24 职场文书
房屋买卖协议书范本
2014/09/27 职场文书
艺术节开幕词
2015/01/28 职场文书
南湾猴岛导游词
2015/02/09 职场文书
2015年学校政教处工作总结
2015/05/26 职场文书
幼儿园开学温馨提示
2015/07/15 职场文书
提取视频中的音频 Python只需要三行代码!
2021/05/10 Python