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

作者:梳碧湖的砍柴人 时间:2024-05-22 10:43:17 

目录
  • 一:搭建webpack

  • 二:数据劫持

  • 三:总结

一:搭建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。

来源:https://juejin.cn/post/6935354560718307365

标签:vue,数据劫持
0
投稿

猜你喜欢

  • Python调用adb命令实现对多台设备同时进行reboot的方法

    2022-08-06 02:40:45
  • Python利用PyExecJS库执行JS函数的案例分析

    2022-10-26 08:53:19
  • selenium中常见的表单元素操作方法总结

    2021-06-15 23:54:32
  • Django 简单实现分页与搜索功能的示例代码

    2023-12-26 01:40:16
  • pip如何用pipdeptree查看包依赖

    2022-07-28 01:56:26
  • javascript修改图片src的方法

    2024-04-17 10:40:29
  • Python实现批量将word转html并将html内容发布至网站的方法

    2021-08-27 04:17:45
  • SQL Server数据库生成与执行SQL脚本详细教程

    2024-01-14 21:50:57
  • Python利用Pydub实现自动分割音频

    2022-10-08 22:02:48
  • TensorFlow实现Batch Normalization

    2023-02-03 05:20:15
  • HTML5 Web Storage全解析

    2010-06-26 13:06:00
  • JPA之映射mysql text类型的问题

    2024-01-17 06:38:41
  • 使用pandas批量处理矢量化字符串的实例讲解

    2023-09-22 03:00:01
  • python爬虫请求头的使用

    2023-03-21 07:10:23
  • Python OpenCV 彩色与灰度图像的转换实现

    2022-04-14 18:36:59
  • Python多线程同步Lock、RLock、Semaphore、Event实例

    2023-08-03 20:47:15
  • 对Python3 pyc 文件的使用详解

    2023-05-02 01:54:57
  • python pygame 愤怒的小鸟游戏示例代码

    2023-11-14 17:00:48
  • asp连接mysql数据库详细实现代码

    2012-12-04 19:56:39
  • golang常用库之配置文件解析库-viper使用详解

    2024-02-17 18:36:46
  • asp之家 网络编程 m.aspxhome.com