手写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


猜你喜欢
Python调用adb命令实现对多台设备同时进行reboot的方法
Python利用PyExecJS库执行JS函数的案例分析

selenium中常见的表单元素操作方法总结

Django 简单实现分页与搜索功能的示例代码

pip如何用pipdeptree查看包依赖

javascript修改图片src的方法
Python实现批量将word转html并将html内容发布至网站的方法
SQL Server数据库生成与执行SQL脚本详细教程

Python利用Pydub实现自动分割音频
TensorFlow实现Batch Normalization

HTML5 Web Storage全解析

JPA之映射mysql text类型的问题
使用pandas批量处理矢量化字符串的实例讲解
python爬虫请求头的使用
Python OpenCV 彩色与灰度图像的转换实现

Python多线程同步Lock、RLock、Semaphore、Event实例

对Python3 pyc 文件的使用详解
python pygame 愤怒的小鸟游戏示例代码

asp连接mysql数据库详细实现代码
golang常用库之配置文件解析库-viper使用详解
