UNPKG

olympus-r

Version:

一个力求简单易用的前端开发框架 #### 开发语言 TypeScript #### 核心架构 MVC #### 模块间通讯和解耦 采用事件机制,利用一个全局唯一的事件派发器进行模块间通讯,解耦模块间依赖 #### 表现层结构 使用桥接模式拆分接口与实现,达到一套核心驱动多套表现层的目的(目前支持DOM、Egret、PixiJS三种表现层),同时支持表现层的未来可扩展性 #### TypeScript装饰器注入 框架提供TypeScript装饰器注入功能,便捷获取托管对象。例如:

547 lines (546 loc) 24.6 kB
import * as tslib_1 from "tslib"; import { core } from "../../core/Core"; import { Injectable } from "../../core/injector/Injector"; import Dictionary from "../../utils/Dictionary"; import { replaceDisplay } from "../../utils/DisplayUtil"; import { extendObject, getObjectHashs } from "../../utils/ObjectUtil"; import { isMediator } from '../mediator/Mediator'; import { netManager } from "../net/NetManager"; import Bind from "./Bind"; import { createRunFunc, evalExp } from "./Utils"; /** * @author Raykid * @email initial_r@qq.com * @create date 2017-11-06 * @modify date 2017-11-06 * * 绑定管理器,可以将数据和显示对象绑定到一起,MVVM书写界面 */ var BindManager = /** @class */ (function () { function BindManager() { this._bindDict = new Dictionary(); this._regExp = /^\s*(\w+)\s+((in)|(of))\s+(.+?)\s*$/; } /** * 获取mediator对应的BindData * * @param {IMediator} mediator * @returns {BindData} * @memberof BindManager */ BindManager.prototype.getBindData = function (mediator) { return this._bindDict.get(mediator); }; /** * 绑定数据到UI上 * * @param {IMediator} mediator 中介者 * @returns {Bind} 返回绑定实例 * @memberof BindManager */ BindManager.prototype.bind = function (mediator) { var bindData = this._bindDict.get(mediator); if (!bindData) { this._bindDict.set(mediator, bindData = { bind: new Bind(mediator), callbacks: [] }); } // 重新绑定所有 for (var _i = 0, _a = bindData.callbacks; _i < _a.length; _i++) { var callback = _a[_i]; callback(); } // 返回Bind对象 return bindData.bind; }; /** * 移除绑定 * * @param {IMediator} mediator * @returns {Bind} * @memberof BindManager */ BindManager.prototype.unbind = function (mediator) { var bindData = this._bindDict.get(mediator); if (bindData) { bindData.bind.dispose(); this._bindDict.delete(mediator); } return bindData && bindData.bind; }; BindManager.prototype.addBindHandler = function (mediator, callback) { var handler = function () { // 判断数据是否合法 if (!mediator.viewModel) return; // 开始绑定 callback(); }; // 添加绑定数据 var bindData = this._bindDict.get(mediator); if (bindData.callbacks.indexOf(handler) < 0) bindData.callbacks.push(handler); // 立即调用一次 handler(); }; BindManager.prototype.getNearestAncestor = function (bridge, target, propName) { if (!target || target[propName]) return target; else return this.getNearestAncestor(bridge, bridge.getParent(target), propName); }; /** * 绑定属性值 * * @param {IMediator} mediator 中介者 * @param {*} currentTarget 绑定到的target实体对象 * @param {*} target 绑定命令本来所在的对象 * @param {any[]} envModels 环境变量数组 * @param {string} name 绑定的属性名 * @param {(EvalExp)} exp 绑定的表达式或方法 * @memberof BindManager */ BindManager.prototype.bindValue = function (mediator, currentTarget, target, envModels, name, exp) { var watcher; var bindData = this._bindDict.get(mediator); this.addBindHandler(mediator, function () { var _a; // 如果之前绑定过,则要先销毁之 if (watcher) watcher.dispose(); // 绑定新的订阅者 watcher = (_a = bindData.bind).createWatcher.apply(_a, [currentTarget, target, exp, function (value) { currentTarget[name] = value; }, mediator.viewModel].concat(envModels, [mediator.viewModel])); }); }; /** * 绑定一个表达式,与bindValue类似,但不会给属性赋值 * * @param {IMediator} mediator 中介者 * @param {*} currentTarget 绑定到的target实体对象 * @param {*} target 绑定命令本来所在的对象 * @param {any[]} envModels 环境变量数组 * @param {(EvalExp)} exp 绑定的表达式或方法 * @memberof BindManager */ BindManager.prototype.bindExp = function (mediator, currentTarget, target, envModels, exp) { var watcher; var bindData = this._bindDict.get(mediator); this.addBindHandler(mediator, function () { var _a; // 如果之前绑定过,则要先销毁之 if (watcher) watcher.dispose(); // 绑定新的订阅者 watcher = (_a = bindData.bind).createWatcher.apply(_a, [currentTarget, target, exp, function (value) { // 不干任何事情 }, mediator.viewModel].concat(envModels, [mediator.viewModel])); }); }; /** * 绑定方法执行 * * @param {IMediator} mediator 中介者 * @param {*} currentTarget 绑定到的target实体对象 * @param {*} target 绑定命令本来所在的对象 * @param {any[]} envModels 环境变量数组 * @param {string} name 绑定的方法名 * @param {...(EvalExp)[]} argExps 执行方法的参数表达式或方法列表 * @memberof BindManager */ BindManager.prototype.bindFunc = function (mediator, currentTarget, target, envModels, name) { var _this = this; var argExps = []; for (var _i = 5; _i < arguments.length; _i++) { argExps[_i - 5] = arguments[_i]; } var watchers = []; var bindData = this._bindDict.get(mediator); this.addBindHandler(mediator, function () { var _a; // 判断参数数量,无参数方法一次性执行即可,无需绑定,有参数的方法则需要每次参数改变就执行一次 if (argExps.length > 0) { // 将表达式中所有undefined和null变为内部值 var undefinedValue = Date.now() * Math.random() + "_undefined"; var nullValue = Date.now() * Math.random() + "_null"; argExps = argExps.map(function (exp) { if (exp === undefined) return "'" + undefinedValue + "'"; else if (exp === null) return "'" + nullValue + "'"; else return exp; }); // 绑定表达式参数数组 var initValue = {}; var args = []; var argsInited = false; var handler = function (index, value) { // 将value中的undefined和null恢复回去 if (value === undefinedValue) value = undefined; else if (value == nullValue) value = null; // 设置参数值 args[index] = value; // 判断参数是否齐全 if (!argsInited) { for (var _i = 0, args_1 = args; _i < args_1.length; _i++) { var arg = args_1[_i]; // 如果列表里存在初始值,表示没有赋值完毕,直接返回 if (arg === initValue) return; } // 设置初始化完毕状态 argsInited = true; } // 赋值已经完毕了,调用方法,this指向ui本身 currentTarget[name].apply(currentTarget, args); }; // 清理旧的订阅者 for (var i = 0, len = watchers.length; i < len; i++) { watchers.shift().dispose(); } // 循环绑定表达式到handler for (var i = 0, len = argExps.length; i < len; i++) { // 记录一个初始值,用于判断参数列表是否已赋值完毕 args.push(initValue); } for (var i = 0, len = argExps.length; i < len; i++) { // 绑定表达式 var watcher = (_a = bindData.bind).createWatcher.apply(_a, [currentTarget, target, argExps[i], handler.bind(_this, i), mediator.viewModel].concat(envModels, [mediator.viewModel])); // 记录订阅者 watchers.push(watcher); } } else { // 无参数执行,无需绑定,一次性执行即可 target[name](); } }); }; /** * 绑定事件 * * @param {IMediator} mediator 中介者 * @param {*} currentTarget 绑定到的target实体对象 * @param {*} target 绑定命令本来所在的对象 * @param {any[]} envModels 环境变量数组 * @param {string} type 绑定的事件类型 * @param {EvalExp} exp 绑定的事件回调表达式或方法 * @memberof BindManager */ BindManager.prototype.bindOn = function (mediator, currentTarget, target, envModels, type, exp) { var _this = this; this.addBindHandler(mediator, function () { var commonScope = { $this: mediator, $data: mediator.viewModel, $bridge: mediator.bridge, $currentTarget: currentTarget, $target: target }; // 计算事件hash var onHash = getObjectHashs(currentTarget, type, exp); // 如果之前添加过监听,则先移除之 var handler = currentTarget[onHash]; if (handler) { mediator.unmapListener(currentTarget, type, handler, mediator.viewModel); handler = null; } // 先尝试用exp当做方法名去viewModel里寻找,如果找不到则把exp当做一个执行表达式处理,外面包一层方法 if (typeof exp === "string") handler = mediator.viewModel[exp]; if (!(handler instanceof Function)) { var func = createRunFunc(exp, 3 + envModels.length); // 这里要转一手,记到闭包里一个副本,否则因为bindOn是延迟操作,到时envModel可能已被修改 handler = function (event) { func.call.apply(func, [this, commonScope].concat(envModels, [mediator.viewModel, { $event: event }])); }; } mediator.mapListener(currentTarget, type, handler, mediator.viewModel); // 将事件回调记录到显示对象上 currentTarget[onHash] = handler; // 如果__bind_sub_events__列表存在,则将事件记录到其上 var nearestAncestor = _this.getNearestAncestor(mediator.bridge, target, "__bind_sub_events__"); var events = (nearestAncestor || target).__bind_sub_events__; if (events) { events.push({ target: currentTarget, type: type, handler: handler, thisArg: mediator.viewModel }); } }); }; /** * 绑定显示 * * @param {IMediator} mediator 中介者 * @param {*} currentTarget 绑定到的target实体对象 * @param {*} target 绑定命令本来所在的对象 * @param {any[]} envModels 环境变量数组 * @param {EvalExp} exp 绑定表达式或方法 * @param {(value:boolean)=>void} [callback] 判断条件改变时会触发这个回调 * @memberof BindManager */ BindManager.prototype.bindIf = function (mediator, currentTarget, target, envModels, exp, callback) { var watcher; var bindData = this._bindDict.get(mediator); var replacer = mediator.bridge.createPlaceHolder(); this.addBindHandler(mediator, function () { var _a; // 如果之前绑定过,则要先销毁之 if (watcher) watcher.dispose(); // 绑定表达式 watcher = (_a = bindData.bind).createWatcher.apply(_a, [currentTarget, target, exp, function (value) { // 如果表达式为true则显示ui,否则移除ui if (value) replaceDisplay(mediator.bridge, replacer, currentTarget); else replaceDisplay(mediator.bridge, currentTarget, replacer); // 触发回调 callback && callback(value); }, mediator.viewModel].concat(envModels, [mediator.viewModel])); }); }; /** * 绑定循环 * * @param {IMediator} mediator 中介者 * @param {*} currentTarget 绑定到的target实体对象 * @param {*} target 绑定命令本来所在的对象 * @param {any[]} envModels 环境变量数组 * @param {string} name 绑定本来所在的对象在Mediator中的名字 * @param {BindForExpType} exp 循环表达式,形如:"a in b"(表示a遍历b中的key)或"a of b"(表示a遍历b中的值)。b可以是个表达式。或者以三元组形式提供,如["a", "in", "b"],其中b可以是表达式,也可以是求值方法 * @param {IMediatorConstructor} [mediatorCls] 提供该参数将使用提供的中介者包装每一个渲染器 * @param {IConstructor} [declaredCls] 声明的类型 * @param {EvalExp} [dataExp] 提供给中介者包装器的数据表达式 * @param {(data:any, renderer:any, envModels:any[])=>void} [callback] 每次生成新的renderer实例时调用这个回调 * @memberof BindManager */ BindManager.prototype.bindFor = function (mediator, currentTarget, target, envModels, name, exp, mediatorCls, declaredCls, dataExp, callback) { var watcher; var bindData = this._bindDict.get(mediator); var subTargetCache = []; var subMediatorCache = []; // 备忘录要在最一开始就生成好,以后就不动了 var expTuple; if (typeof exp === "string") { // 字符串形式,解析表达式 var res = this._regExp.exec(exp); if (!res) return; expTuple = [res[1], res[2], res[5]]; } else { // 元组形式,直接赋值 expTuple = exp; } // 如果给出了声明的Mediator类型,则生成一个声明Mediator,替换掉mediator当前的皮肤 var declaredMediator; if (isMediator(declaredCls.prototype)) { declaredMediator = new declaredCls(target); mediator.delegateMediator(declaredMediator); mediator[name] = declaredMediator; } else if (declaredCls === Array) { if (mediatorCls) { // 如果规定了变身中介者,则将该属性变成中介者列表 mediator[name] = subMediatorCache; } else { // 否则变成渲染器对象列表 mediator[name] = subTargetCache; } } // 包装渲染器创建回调 var memento = mediator.bridge.wrapBindFor(currentTarget, function (key, value, renderer) { // 设置环境变量 var subScope = { $key: key, $value: value, $parent: envModels[0] || mediator.viewModel }; // 填入用户声明的属性 subScope[expTuple[0]] = (expTuple[1] == "in" ? key : value); // 生成一个环境变量的副本 var subEnvModels = envModels.concat(); // 插入环境变量 subEnvModels.unshift(subScope); // 如果renderer已经有事件列表了,说明renderer是被重用的,删除所有事件 var events = renderer.__bind_sub_events__; for (var i in events) { var data = events.pop(); mediator.unmapListener(data.target, data.type, data.handler, data.thisArg); } // 为renderer设置子对象事件列表 if (!events) renderer.__bind_sub_events__ = []; // 为renderer套一个Mediator外壳 if (mediatorCls) { var subMediator = new mediatorCls(renderer); // 更新渲染器 if (subMediator.skin && subMediator.bridge === mediator.bridge) renderer = subMediator.skin; // 托管子中介者,优先托管在声明出来的中间中介者上 (declaredMediator || mediator).delegateMediator(subMediator); // 设置通用属性 var commonScope = { $this: mediator, $data: mediator.viewModel, $bridge: mediator.bridge, $currentTarget: currentTarget, $target: target }; // 开启该中介者,优先使用dataExp,如果没有则使用当前所有的数据 var data_1; if (dataExp) { // 有数据表达式,求出数据表达式的值来 data_1 = evalExp.apply(void 0, [dataExp, mediator.viewModel].concat(subEnvModels.concat().reverse(), [mediator.viewModel, commonScope])); } else { // 没有数据表达式,套用当前所在变量域,且要打平做成一个data data_1 = extendObject.apply(void 0, [{}, commonScope, mediator.viewModel].concat(subEnvModels)); } subMediator.open(data_1); // 缓存子中介者 subMediatorCache.push(subMediator); } else { // 缓存渲染器对象 subTargetCache.push(renderer); } // 触发回调,进行内部编译 callback && callback(value, renderer, subEnvModels); }); this.addBindHandler(mediator, function () { var _a; // 如果之前绑定过,则要先销毁之 if (watcher) watcher.dispose(); // 获得要遍历的数据集合 watcher = (_a = bindData.bind).createWatcher.apply(_a, [currentTarget, target, expTuple[2], function (datas) { // 如果遍历的对象是个数字,则伪造一个临时数组供使用 if (typeof datas === "number") { var tempArr = []; for (var i = 0; i < datas; i++) { tempArr.push(i); } datas = tempArr; } // 清空已有的子中介者 for (var i = 0, len = subMediatorCache.length; i < len; i++) { var subMediator = subMediatorCache.shift(); mediator.undelegateMediator(subMediator); subMediator.dispose(); } // 清空已有缓存对象 for (var i = 0, len = subTargetCache.length; i < len; i++) { subTargetCache.shift(); } // 赋值 mediator.bridge.valuateBindFor(currentTarget, datas, memento); }, mediator.viewModel].concat(envModels, [mediator.viewModel])); }); }; /** * 绑定Message * * @param {IMediator} mediator 中介者 * @param {*} currentTarget 绑定到的target实体对象 * @param {*} target 绑定命令本来所在的对象 * @param {any[]} envModels 环境变量数组 * @param {IConstructor|string} type 绑定的消息类型字符串 * @param {string} name 绑定的属性名 * @param {EvalExp} exp 绑定的表达式或方法 * @param {IObservable} [observable] 绑定的消息内核,默认是core * @memberof BindManager */ BindManager.prototype.bindMessage = function (mediator, currentTarget, target, envModels, type, name, exp, observable) { if (!observable) observable = core.observable; var handler = function () { var args = []; for (var _i = 0; _i < arguments.length; _i++) { args[_i] = arguments[_i]; } if (mediator.disposed) { // mediator已销毁,取消监听 observable.unlisten(type, handler); } else { var msg; if (args.length == 1 && typeof args[0] == "object" && args[0].type) msg = args[0]; else msg = { $arguments: args }; // 设置通用属性 var commonScope = { $this: mediator, $data: mediator.viewModel, $bridge: mediator.bridge, $currentTarget: currentTarget, $target: target }; currentTarget[name] = evalExp.apply(void 0, [exp, mediator.viewModel, msg].concat(envModels, [mediator.viewModel, commonScope])); } }; // 添加监听 observable.listen(type, handler); }; /** * 绑定Response * * @param {IMediator} mediator 中介者 * @param {*} currentTarget 绑定到的target实体对象 * @param {*} target 绑定命令本来所在的对象 * @param {any[]} envModels 环境变量数组 * @param {IResponseDataConstructor|string} type 绑定的通讯消息类型 * @param {string} name 绑定的属性名 * @param {EvalExp} exp 绑定的表达式或方法 * @param {IObservable} [observable] 绑定的消息内核,默认是core * @memberof BindManager */ BindManager.prototype.bindResponse = function (mediator, currentTarget, target, envModels, type, name, exp, observable) { if (!observable) observable = core.observable; var handler = function (response) { if (mediator.disposed) { // mediator已销毁,取消监听 netManager.unlistenResponse(type, handler, null, null, observable); } else { // 设置通用属性 var commonScope = { $this: mediator, $data: mediator.viewModel, $bridge: mediator.bridge, $currentTarget: currentTarget, $target: target }; currentTarget[name] = evalExp.apply(void 0, [exp, mediator.viewModel, response].concat(envModels, [mediator.viewModel, commonScope])); } }; // 添加监听 netManager.listenResponse(type, handler, null, null, observable); // 如果mediator所依赖的模块有初始化消息,则要额外触发初始化消息的绑定 if (mediator["dependModuleInstance"]) { for (var _i = 0, _a = mediator["dependModuleInstance"].responses; _i < _a.length; _i++) { var response = _a[_i]; handler(response); } } }; BindManager = tslib_1.__decorate([ Injectable ], BindManager); return BindManager; }()); export default BindManager; /** 再额外导出一个单例 */ export var bindManager = core.getInject(BindManager);