olympus-r
Version:
一个力求简单易用的前端开发框架 #### 开发语言 TypeScript #### 核心架构 MVC #### 模块间通讯和解耦 采用事件机制,利用一个全局唯一的事件派发器进行模块间通讯,解耦模块间依赖 #### 表现层结构 使用桥接模式拆分接口与实现,达到一套核心驱动多套表现层的目的(目前支持DOM、Egret、PixiJS三种表现层),同时支持表现层的未来可扩展性 #### TypeScript装饰器注入 框架提供TypeScript装饰器注入功能,便捷获取托管对象。例如:
268 lines (267 loc) • 9.39 kB
JavaScript
import { getObjectHashs } from "../../utils/ObjectUtil";
import Dep from "./Dep";
import Watcher from "./Watcher";
/**
* @author Raykid
* @email initial_r@qq.com
* @create date 2017-11-06
* @modify date 2017-11-06
*
* 变异器,将ViewModel变异为具有依赖功能的形式,也可以认为是编译过程
*/
// 记录数组中会造成数据更新的所有方法名
var arrMethods = [
"push",
"pop",
"unshift",
"shift",
"splice",
"sort",
"reverse"
];
/**
* 将用户传进来的数据“变异”成为具有截获数据变更能力的数据
* @param data 原始数据
* @returns {any} 变异后的数据
*/
export function mutate(data) {
// 如果是简单类型,则啥也不做
if (!data || typeof data != "object")
return data;
// 递归变异所有内部变量,及其__proto__下的属性,因为getter/setter会被定义在__proto__上,而不是当前对象上
var keys = Object.keys(data).concat(Object.keys(data.__proto__ || {}));
// 去重
var temp = {};
for (var _i = 0, keys_1 = keys; _i < keys_1.length; _i++) {
var key = keys_1[_i];
if (!temp[key]) {
temp[key] = key;
// 递归变异
mutateObject(data, key);
}
}
return data;
}
/**
* 反变异,将已经变异过的对象恢复原状
*
* @author Raykid
* @date 2019-02-19
* @export
* @param {*} data
* @returns {*}
*/
export function unmutate(data) {
// 如果是简单类型,则啥也不做
if (!data || typeof data != "object")
return data;
// 递归变异所有内部变量,及其__proto__下的属性,因为getter/setter会被定义在__proto__上,而不是当前对象上
var keys = Object.keys(data).concat(Object.keys(data.__proto__ || {}));
// 去重
var temp = {};
for (var _i = 0, keys_2 = keys; _i < keys_2.length; _i++) {
var key = keys_2[_i];
if (!temp[key]) {
temp[key] = key;
// 递归反变异
unmutateObject(data, key);
}
}
return data;
}
function onGet(dep, result, mutateSub) {
// 如果Watcher.updating不是null,说明当前正在执行表达式,那么获取的变量自然是其需要依赖的
var watcher = Watcher.updating;
if (watcher)
dep.watch(watcher);
// 首次获取需要变异
if (mutateSub) {
// 如果是数组就走专门的数组变异方法,否则递归变异对象
if (Array.isArray(result))
mutateArray(result, dep);
else
mutate(result);
}
}
function onSet(dep, value) {
// 如果是数组就走专门的数组变异方法,否则递归变异对象
if (Array.isArray(value))
mutateArray(value, dep);
else
mutate(value);
// 触发通知
dep.notify();
}
function mutateObject(data, key) {
var depKey = getObjectHashs(data, key);
// 对每个复杂类型对象都要有一个对应的依赖列表
var dep = data[depKey];
var mutateSub = true;
if (!dep) {
dep = new Dep();
// 判断本来这个属性是值属性还是getter/setter属性,要有不同的操作方式
var desc = Object.getOwnPropertyDescriptor(data, key) || Object.getOwnPropertyDescriptor(data.__proto__ || {}, key);
if (desc) {
// 开始变异当前属性
if (desc.hasOwnProperty("value")) {
// 值属性的变异过程
Object.defineProperty(data, key, {
enumerable: true,
configurable: true,
get: function () {
// 利用闭包保存原始值
var result = desc.value;
// 执行处理
onGet(dep, result, mutateSub);
// 设置标记
mutateSub = false;
// 返回值
return result;
},
set: function (value) {
if (!desc.writable || value === desc.value)
return;
desc.value = value;
// 执行处理
onSet(dep, value);
}
});
}
else {
// getter/setter属性的变异过程
Object.defineProperty(data, key, {
enumerable: true,
configurable: true,
get: function () {
if (!desc.get)
return;
// 获取get方法结果
var result = desc.get.call(data);
// 执行处理
onGet(dep, result, mutateSub);
// 设置标记
mutateSub = false;
// 返回值
return result;
},
set: function (value) {
if (!desc.set)
return;
// 设置
desc.set.call(data, value);
// 执行处理
onSet(dep, value);
}
});
}
}
// 打一个标记表示已经变异过了
Object.defineProperty(data, depKey, {
value: dep,
writable: false,
enumerable: false,
configurable: true
});
Object.defineProperty(data, depKey + "|oriDesc", {
value: desc,
writable: false,
enumerable: false,
configurable: true
});
}
}
function unmutateObject(data, key) {
var depKey = getObjectHashs(data, key);
// 对每个复杂类型对象都要有一个对应的依赖列表
var dep = data[depKey];
if (dep) {
var target = data[key];
// 深度优先递归反变异
if (target instanceof Array) {
unmutateArray(target, dep);
}
else {
unmutate(target);
}
// 开始反变异自身
var desc = data[depKey + "|oriDesc"];
Object.defineProperty(data, key, desc);
// 移除标记
delete data[depKey];
delete data[depKey + "|oriDesc"];
}
}
function mutateArray(arr, dep) {
// 变异当前数组
Object.setPrototypeOf(arr, defineReactiveArray(dep));
// 遍历当前数组,将内容对象全部变异
for (var i = 0, len = arr.length; i < len; i++) {
mutate(arr[i]);
}
}
function unmutateArray(arr, dep) {
// 遍历当前数组,将内容对象全部反变异
for (var i = 0, len = arr.length; i < len; i++) {
unmutate(arr[i]);
}
// 反变异当前数组
Object.setPrototypeOf(arr, Array.prototype);
}
function defineReactiveArray(dep) {
var proto = Array.prototype;
var result = Object.create(proto);
// 遍历所有方法,一个一个地变异
arrMethods.forEach(function (method) {
// 利用闭包记录一个原始方法
var oriMethod = proto[method];
// 开始变异
Object.defineProperty(result, method, {
value: function () {
var args = [];
for (var _i = 0; _i < arguments.length; _i++) {
args[_i] = arguments[_i];
}
// 首先调用原始方法,获取返回值
var result = oriMethod.apply(this, args);
// 数组插入项
var inserted;
switch (method) {
case "push":
case "unshift":
inserted = args;
break;
case "splice":
inserted = args.slice(2);
break;
}
// 监视数组插入项,而不是重新监视整个数组
if (inserted && inserted.length) {
mutateArray(inserted, dep);
}
// 触发更新
dep.notify({ method: args });
// 返回值
return result;
}
});
});
// 提供替换数组设置的方法,因为直接设置数组下标的方式无法变异
Object.defineProperty(result, "$set", {
value: function (index, value) {
// 超出数组长度默认追加到最后
if (index >= this.length)
index = this.length;
return this.splice(index, 1, value)[0];
}
});
// 提供替换数组移除的方法,因为直接移除的方式无法变异
Object.defineProperty(result, "$remove", {
value: function (item) {
var index = this.indexOf(item);
if (index > -1)
return this.splice(index, 1);
return null;
}
});
return result;
}