Vue数据驱动模拟实现4


Posted in Javascript onJanuary 12, 2017

一、前言

在"模拟Vue之数据驱动3"中,我们实现了为每个对象扩展一个$set方法,用于新增属性使用,这样就可以监听新增的属性了。

当然,数组也是对象,也可以通过$set方法实现新增属性。

但是,对于数组而言,通常我们是通过push之类的方法吧。

PS:Vue中明确指出push、pop、shift、unshift、splice、sort、reverse方法为变异方法,可以通过它们监听属性变化,触发视图更新(详情见here)

下面,我们就一起来实现这些Array的变异方法吧。

注:我们将Array变异方法实现,也写在extendObj.js中的,因为数组也是对象嘛。

二、Array变异方法实现

要实现这些变异方法,毫无疑问,我们会重写它们,那在Array.prototype里面重写吗?

当然不是,这样不就影响了所有数组对象的原型链了么!

为了避免这种情况,且,我们只是想在监听数据对象上继承这些变异数组方法,那么细心的你会发现,其实与我们在"模拟Vue之数据驱动3"中实现$set方法类似了。

首先,我们创建arrKeys对象用于保存需要变异的数组方法以及恒定对象extendArr,如下:

let arrKeys = ['push', 'pop', 'shift', 'unshift', 'splice', 'sort', 'reverse'];
const extendArr = [];

接着,就是在extendArr对象上,一一监听arrKeys中的方法了,与$set方法类似,整体结构如下:

!function(){
  arrKeys.forEach(function(key){
    proxyObject(extendArr, key, function(){
      //TODO
    });
  });
}();

注:proxyObject方法其实核心就是Object.defineProperty,详见"模拟Vue之数据驱动3".

接下来,就是实现核心部分代码了,重写这些方法的目的,是为了监听数据变化,所以要在方法原有功能不变的情况下,重写它们,Array.xxx.apply即可实现原有功能。

且,push、unshift、splice这三个方法可以在原数组中,新增属性,故而,我们需要监听新增属性以及它们的属性值,这里就和$set方法完全一样了,通过$Observer,即可利用observe以及convert方法实现了。

实现代码如下:

!function(){
  arrKeys.forEach(function(key){
    proxyObject(extendArr, key, function(){
      console.log('Fun ' + key + ' is observed');
      let result;
      let arrProto = Array.prototype;
      let ob = this.$Observer;
      let arr = arrProto.slice.call(arguments);
      let inserted;
      let index;
      switch(key){
        case 'push': {
          inserted = arr;
          index = this.length;
          break;
        }
        case 'unshift': {
          inserted = arr;
          index = 0;
          break;
        }
        case 'splice': {
          inserted = arr.slice(2);
          index = arr[0];
          break;
        }
      }
      result = arrProto[key].apply(this, arguments);
      if(inserted){
        inserted.forEach(val => {
          ob.observe(val);
          ob.convert(index++, val);
        });
      }
      return result;
    });
  });
}();

最后,就是在需要监听的对象上继承这些变异方法咯,如下:

//observer.js
function Observer(data){
  if(!(this instanceof Observer)){
    return new Observer(data);
  }
  data.__proto__ = extendObj;
  //继承变异方法push、pop等等
  if(Array.isArray(data)){
    data.__proto__.__proto__ = extendArr;
  }
  this.data = data;
  this.walk(data);  
}

好了,一切完毕,接下来就测试下呗:

<script src="./extendObj.js"></script>
<script src="./observer.js"></script>
<script>
  'use strict';
  let data = {
    msg: [5, 2, 0],
    user: {
      name: 'Monkey',
      age: 24
    },
    lover: {
      name: 'Dorie',
      age: 23
    }
  };
  Observer(data);
</script>

效果如下:

Vue数据驱动模拟实现4

Perfect,此时,你可能会想,数组方法中仅有push、unshift、splice会为数组新增属性,那么我们又何必将其他方法,例如sort、reverse重写呢,也没发现有什么猫腻呢?

不错,在此时,并没有什么卵用,但是,你要知道sort、reverse等这些方法,可是会引起数组变化的,那么就会影响视图展现,这些变化,又怎么通知数组呢?就是下篇随笔会具体说明的。

该篇随笔代码,详情见github.

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
分别用marquee和div+js实现首尾相连循环滚动效果,仅3行代码
Sep 21 Javascript
推荐40个非常优秀的jQuery插件和教程【系列三】
Nov 09 Javascript
JS给Textarea文本框添加行号的方法
Aug 20 Javascript
jQuery弹层插件jquery.fancybox.js用法实例
Jan 22 Javascript
javascript点击按钮实现隐藏显示切换效果
Feb 03 Javascript
vue.js计算属性computed用法实例分析
Jul 06 Javascript
vue2.0 element-ui中el-select选择器无法显示选中的内容(解决方法)
Aug 24 Javascript
详解如何用VUE写一个多用模态框组件模版
Sep 27 Javascript
详解JS取出两个数组中的不同或相同元素
Mar 20 Javascript
Openlayers实现点闪烁扩散效果
Sep 24 Javascript
vue使用transition组件动画效果的实例代码
Jan 28 Vue.js
如何使JavaScript休眠或等待
Apr 27 Javascript
移动端点击态处理的三种实现方式
Jan 12 #Javascript
js手机号批量滚动抽奖实现代码
Apr 17 #Javascript
js图片轮播手动切换特效
Jan 12 #Javascript
原生js实现倒计时功能(多种格式调用)
Jan 12 #Javascript
JavaScript定义全局对象的方法示例
Jan 12 #Javascript
Node.js制作简单聊天室
Jan 12 #Javascript
jQuery 插件实现随机自由弹跳气泡样式
Jan 12 #Javascript
You might like
使用PHP制作新闻系统的思路
2006/10/09 PHP
smarty 缓存控制前的页面静态化原理
2013/03/15 PHP
destoon切换城市后实现logo旁边显示地区名称的方法
2014/08/21 PHP
php使用cookie实现记住用户名和密码实现代码
2015/04/27 PHP
Yii视图CGridView列表用法实例分析
2016/07/12 PHP
返回顶部按钮响应滚动且动态显示与隐藏
2014/10/14 Javascript
javascript实现相同事件名称,不同命名空间的调用方法
2015/06/26 Javascript
超漂亮的Bootstrap 富文本编辑器summernote
2016/04/05 Javascript
JS动态给对象添加属性和值的实现方法
2016/10/21 Javascript
js图片放大镜效果实现方法详解
2020/10/28 Javascript
jQuery选择器特殊字符与属性空格问题
2017/08/14 jQuery
jQuery表单元素过滤选择器用法实例分析
2019/02/20 jQuery
详解key在Vue列表渲染时究竟起到了什么作用
2019/04/20 Javascript
解决Vue.js应用回退或刷新界面时提示用户保存修改问题
2019/11/24 Javascript
vue 使用外部JS与调用原生API操作示例
2019/12/02 Javascript
React实现全选功能
2020/08/25 Javascript
vue v-on:click传递动态参数的步骤
2020/09/11 Javascript
python实现bitmap数据结构详解
2014/02/17 Python
Python聚类算法之凝聚层次聚类实例分析
2015/11/20 Python
如何使用python爬取csdn博客访问量
2016/02/14 Python
Python中matplotlib中文乱码解决办法
2017/05/12 Python
Python实现的圆形绘制(画圆)示例
2018/01/31 Python
Python+OpenCV图片局部区域像素值处理改进版详解
2019/01/23 Python
通过 Django Pagination 实现简单分页功能
2019/11/11 Python
NumPy排序的实现
2020/01/21 Python
在tensorflow中设置使用某一块GPU、多GPU、CPU的操作
2020/02/07 Python
原生 JS+CSS+HTML 实现时序图的方法
2019/07/31 HTML / CSS
美国孕妇装购物网站:Motherhood Maternity
2019/09/22 全球购物
美国办公用品折扣网站:Shoplet.com
2019/11/24 全球购物
美国相机和电子产品零售商:Beach Camera
2020/11/26 全球购物
全球性的众包图形设计市场:DesignCrowd
2021/02/02 全球购物
JVM是一个编译程序还是解释程序
2012/09/11 面试题
数学系个人求职信范文
2014/01/30 职场文书
音乐教师求职信
2014/06/28 职场文书
机票销售员态度不好检讨书
2014/09/27 职场文书
三方股东合作协议书范本
2014/09/28 职场文书