手写Vue2.0 数据劫持的示例


Posted in Vue.js onMarch 04, 2021

一:搭建webpack

简单的搭建一下webpack的配置。新建一个文件夹,然后init一下。之后新建一个webpack.config.js文件,这是webpack的配置文件。安装一下简单的依赖。

npm install webpack webpack-cli webpack-dev-server -D

在同级目录下新建一个public/index.html和src/index.js,作为出口文件和入口文件。

j简单配置一下webpack, 在webpack.config.js文件中:

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
 entry: './src/index.js',
 output: {
  filename: 'bundle.js',
  path: path.resolve(__dirname, 'dist')
 },
 resolve: { 
  modules: [
  path.resolve(__dirname, ''), path.resolve(__dirname, 'node_modules')  
  ] 
 },
 plugins: [  
  new HtmlWebpackPlugin({   
   template: path.resolve(__dirname, 'public/index.html')  
  }) 
 ]
}

ok,基本配置好webpack就可以开始正题了。

二:数据劫持

在v2中,通过new Vue(el, options)的方式,完成vue的实例化。我们需要新建一下vue文件,把数据劫持的方法统一到vue中。

新建一个vue/index.js,作为数据劫持的入口文件。

import {initState} from './init.js';

function Vue (options) {
 this._init(options);  // 数据初始化
}
Vue.prototype._init = function (options) {
 var vm = options; // 保存一下实例
 vm.$options = options; // 实例挂载
 initState(vm);   // 实例初始化
}

新建一个init.js文件初始化实例:

初始化的时候注意几个问题: 

1.  需要分别对computed,watch, data进行处理。

2. 不要在用户定义的data上直接修改。

3. 官方指定data为函数,是为了保证组件内部有自己的作用域不会有污染,直接访问data函数是不行的,需要自动执行。data也可以是对象(需要考虑到这个情况)

4. 这种方式获取data是通过vm._data.xxx 但是在vue中不需要data来获取,所以这里需要拦截重写。

5. 内部的引用类型需要递归

function initState (vm) {
 var options = vm.$options; // 获取options
 if (options.data) {
  initData(vm); // 因为computed,watch都需要在这里初始化,所以针对data初始化
};

function initData (vm) {
 var data = vm.$options.data; // 对data重新赋值,不要改变用户定义的data
 data = vm._data = typeof data === 'function' ? data.call(vm) : data || {};
 for (var key in data) {
  proxyData(vm, '_data', key);   // 对data的取值重新赋值
 };
 observe(vm._data); // 对data内部进行观察
}

新建一个proxy.js作为代理层:

function proxyData(vm, target, key) { 
 Object.defineProperty(vm, key, {  
   get () {   
   // 这里做了拦截: vm.xxx => vm._data.xxx   
   return vm[target][key];  
  },  
  set(newValue) {   
   // vm.xxx = yyy ===> vm._data.title = yyy   
   vm[target][key] = newValue;  
  } 
 }) 
}
export default proxyData;

处理好了访问问题,现在需要递归一下data内部元素。obseve(vm._data);

新建一个observe.js:

function observe (data) {
 if (typeof data !== 'object' || data = null) return;
 return new Observer(data); // 如果是应用类型,直接添加一个观察者
}

新建一个观察者:observer.js

function Observer(data) {
 if (Array.isArray(data)) {
  // 处理数组
   data._proto_ = arrMethods; 
 }
 else {
  // 处理对象
  this.walks(data);
 }
}
Observer.prototype.walks = function (data) {
 let keys = Object.keys(data); // 拿到data下面所有的key,并且还是一个数组
 for (var i = 0 ; i < keys.length ; i++) {  
  var key = keys[i];  
  var value = data[key];  
  defineReactiveData(data, key, value); // 每个重新生成响应式数据 
 }}

新建一个reactive.js 处理对象等响应式

function defineReactiveData (data, key, value) { 
 observe(value);  // 对子元素接着递归。 
 Object.defineProperty(data, key, {  
  get() {   
   return value;  
  },  
  set (newValue) {   
   if (newValue === value) return;   
   value = newValue;  // 触发更改  
  } 
 }
 )
};

ok,这里处理好了对象的数据劫持,剩余的需要处理数组了

在V2中采用重写原型上的7种方法,做到数据劫持。

劫持数组:

新建一个Array.js文件:

import {ARR_METHODS} from './config.js';  
 // 7个数组方法的合集
import observeArr from './observeArr.js';
var originArrMethods = Array.prototype, 
arrMethods = Object.create(originArrMethods); 
ARR_METHODS.map(function (m) { 
 arrMethods[m] = function () {  
  var args = Array.prototype.slice.call(arguments); // 类数组转为数组  
  var rt = originArrMethods[m].apply(this, args);  
  var newArr;  
  switch (m) {   
   case 'push':   
   case 'ushift':     
    newArr = args;   
   case 'splice':    
    newArr = args.slice(2);    
    break;   
   default:     
    break;  };  
  newArr && observeArr(newArr);  
  return rt; 
  } 
}); 
 export { arrMethods }

observeArr(newArr): 数组也可能有嵌套,所以需要对数据进行观察。

import observe from "./observe";
function observeArr (arr) { 
 for (var i = 0 ; i < arr.length ; i++) {  
  observe(arr[i]); // 重新走到了observe上。 
 }
}
export default observeArr;

三:总结

 基本流程就是这样的,不仅仅是object.defineProperty对数据进行get和set这么简单。总结一下主要流程:

(1): 在初始化的时候:保存一下实例,挂载实例。通过initState方法来初始化数据,这里主要是data数据,也有computed和watch需要处理。

(2): 调用initData(); 重新赋值data,然后执行data,修改用户获取data属性的写法统一为this.xxx同时observe(data)

(3):在observe(data)的时候需要对data进行判断,如果是引用类型需要加上一个观察者observer,同时在观察者终判断data是为数组还是对象,对象直接重新触发object.defineProperty,同时对内部重新observe。如果是数组直接重新7种数组方法,然后对数组内部接着observe。

以上就是手写Vue2.0 数据劫持的示例的详细内容,更多关于手写vue 数据劫持的资料请关注三水点靠木其它相关文章!

Vue.js 相关文章推荐
vue开发chrome插件,实现获取界面数据和保存到数据库功能
Dec 01 Vue.js
基于vue项目设置resolves.alias: '@'路径并适配webstorm
Dec 02 Vue.js
Vue3 实现双盒子定位Overlay的示例
Dec 22 Vue.js
vue实现简易的双向数据绑定
Dec 29 Vue.js
vue 动态生成拓扑图的示例
Jan 03 Vue.js
vue项目如何监听localStorage或sessionStorage的变化
Jan 04 Vue.js
vue编写简单的购物车功能
Jan 08 Vue.js
Vue实现一种简单的无限循环滚动动画的示例
Jan 10 Vue.js
Vue3 Composition API的使用简介
Mar 29 Vue.js
vue实现水波涟漪效果的点击反馈指令
May 31 Vue.js
vue使用echarts实现折线图
Mar 21 Vue.js
vue实力踩坑之push当前页无效
Apr 10 Vue.js
vue3.0封装轮播图组件的步骤
Mar 04 #Vue.js
vue3.0 项目搭建和使用流程
Mar 04 #Vue.js
vue 数据双向绑定的实现方法
Mar 04 #Vue.js
vue3.0中使用element的完整步骤
Mar 04 #Vue.js
VUE实现吸底按钮
Mar 04 #Vue.js
vue实现可移动的悬浮按钮
Mar 04 #Vue.js
vue中axios封装使用的完整教程
Mar 03 #Vue.js
You might like
两种php给图片加水印的实现代码
2020/04/18 PHP
php之header的不同用法总结(实例讲解)
2017/11/28 PHP
JS中彻底删除JSON对象组成的数组中的元素
2020/09/22 PHP
锋利的jQuery 要点归纳(一) jQuery选择器
2010/03/21 Javascript
40款非常棒的jQuery 插件和制作教程(系列一)
2011/10/26 Javascript
兼容IE和Firefox火狐的上下、左右循环无间断滚动JS代码
2013/04/19 Javascript
js charAt的使用示例
2014/02/18 Javascript
JS生成随机字符串的多种方法
2014/06/10 Javascript
jQuery关键词说明插件cluetip使用指南
2015/04/21 Javascript
node.js+express制作网页计算器
2016/01/17 Javascript
js获取页面及个元素高度、宽度的代码
2016/04/26 Javascript
jQuery基于ID调用指定iframe页面内的方法
2016/07/06 Javascript
微信小程序 本地存储及登录页面处理实例详解
2017/01/11 Javascript
Bootstrap fileinput文件上传组件使用详解
2017/06/06 Javascript
Javascript和jquery在selenium的使用过程
2019/10/31 jQuery
解决微信授权成功后点击按返回键出现空白页和报错的问题
2020/06/08 Javascript
[01:03:37]Secret vs VGJ.S Supermajor小组赛C组 BO3 第二场 6.3
2018/06/04 DOTA
[01:01:43]EG vs VP 2018国际邀请赛淘汰赛BO3 第二场 8.24
2018/08/25 DOTA
python学习 流程控制语句详解
2016/06/01 Python
Python实现的爬虫功能代码
2017/06/24 Python
和孩子一起学习python之变量命名规则
2018/05/27 Python
Python操作json的方法实例分析
2018/12/06 Python
python导入模块交叉引用的方法
2019/01/19 Python
pycharm 更改创建文件默认路径的操作
2020/02/15 Python
Django Xadmin多对多字段过滤实例
2020/04/07 Python
python利用platform模块获取系统信息
2020/10/09 Python
python 获取字典键值对的实现
2020/11/12 Python
Django-silk性能测试工具安装及使用解析
2020/11/28 Python
python爬虫beautifulsoup库使用操作教程全解(python爬虫基础入门)
2021/02/19 Python
HTML5 video视频字幕的使用和制作方法
2018/05/03 HTML / CSS
大学生演讲稿范文
2014/01/11 职场文书
2014年小学生教师节演讲稿范文
2014/09/10 职场文书
作风建设年度心得体会
2014/10/29 职场文书
小学少先队工作总结2015
2015/05/26 职场文书
动视暴雪取消疫苗禁令 让所有员工返回线下工作
2022/04/03 其他游戏
JavaScript架构localStorage特殊场景下二次封装操作
2022/06/21 Javascript