关于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 elementUI 使用el-select 时 change事件的触发问题
Nov 17 Vue.js
vue表单验证之禁止input输入框输入空格
Dec 03 Vue.js
Vue实现一种简单的无限循环滚动动画的示例
Jan 10 Vue.js
VUE实现吸底按钮
Mar 04 Vue.js
详细聊聊vue中组件的props属性
Nov 02 Vue.js
详解Vue项目的打包方式(生成dist文件)
Jan 18 Vue.js
vue3获取当前路由地址
Feb 18 Vue.js
vue使用echarts实现折线图
Mar 21 Vue.js
vue整合百度地图显示指定地点信息
Apr 06 Vue.js
解决vue自定义组件@click点击失效问题
Apr 30 Vue.js
vue中data里面的数据相互使用方式
Jun 05 Vue.js
vue如何在data中引入图片的正确路径
Jun 05 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
海贼王动画变成“真人”后,凯多神还原,雷利太帅了!
2020/04/09 日漫
新手学PHP之数据库操作详解及乱码解决!
2007/01/02 PHP
php中Socket创建与监听实现方法
2015/01/05 PHP
PHP开发中csrf攻击的简单演示和防范
2017/05/07 PHP
php 中的closure用法详解
2017/06/12 PHP
浅谈PHP5.6 与 PHP7.0 区别
2019/10/09 PHP
经验几则 推荐
2006/09/05 Javascript
JS 继承实例分析
2008/11/04 Javascript
JS Pro-深入面向对象的程序设计之继承的详解
2013/05/07 Javascript
Function.prototype.call.apply结合用法分析示例
2013/07/03 Javascript
javascript判断两个IP地址是否在同一个网段的实现思路
2013/12/13 Javascript
JavaScript中的关联数组问题
2015/03/04 Javascript
AngularJS递归指令实现Tree View效果示例
2016/11/07 Javascript
JavaScript中的编码和解码函数
2017/02/15 Javascript
深究AngularJS中ng-drag、ng-drop的用法
2017/06/12 Javascript
详解webpack提取第三方库的正确姿势
2017/12/22 Javascript
基于vue-cli npm run build之后vendor.js文件过大的解决方法
2018/09/27 Javascript
微信小程序 下拉刷新及上拉加载原理解析
2019/11/06 Javascript
vue-cli设置css不生效的解决方法
2020/02/07 Javascript
vue+axios 拦截器实现统一token的案例
2020/09/11 Javascript
python线程池的实现实例
2013/11/18 Python
python文件和目录操作方法大全(含实例)
2014/03/12 Python
Python的Bottle框架中实现最基本的get和post的方法的教程
2015/04/30 Python
Python遍历目录中的所有文件的方法
2016/07/08 Python
Win10系统下安装labelme及json文件批量转化方法
2019/07/30 Python
Django 通过JS实现ajax过程详解
2019/07/30 Python
500行代码使用python写个微信小游戏飞机大战游戏
2019/10/16 Python
关于ZeroMQ 三种模式python3实现方式
2019/12/23 Python
阿根廷网上配眼镜:SmartBuyGlasses阿根廷
2016/08/19 全球购物
美国珠宝网上商店:Jeulia
2016/09/01 全球购物
Roxy俄罗斯官方网站:冲浪和滑雪板的一切
2020/06/20 全球购物
建筑工程实习自我鉴定
2013/09/19 职场文书
改作风抓落实促发展心得体会
2014/09/10 职场文书
2014年社区民政工作总结
2014/12/02 职场文书
实习工作表现评语
2014/12/31 职场文书
Linux中sftp常用命令整理
2022/06/28 Servers