UNPKG

mtor

Version:

react 模块化 依赖注入 数据流处理

359 lines 13.6 kB
"use strict"; var __assign = (this && this.__assign) || function () { __assign = Object.assign || function(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; var __spreadArrays = (this && this.__spreadArrays) || function () { for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length; for (var r = Array(s), k = 0, i = 0; i < il; i++) for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++) r[k] = a[j]; return r; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.useInitModel = exports.getModels = exports.Model = exports.resource = exports.inject = exports.useModel = exports.service = exports.define = void 0; /** * mtor * Copyright (c) 2021 Sampson Li (lichun) <740056710@qq.com> * @license MIT */ var react_1 = require("react"); var util_1 = require("./util"); var EventBus_1 = require("./EventBus"); // 导出事件总线实例,供外部使用 var EventBus_2 = require("./EventBus"); Object.defineProperty(exports, "evtBus", { enumerable: true, get: function () { return EventBus_2.eventBus; } }); /** * 全局存储对象,用于管理所有模块实例 */ // 保存所有模块的原型对象,键为模块名称,值为模块原型 var allProto = {}; // 保存所有模块的静态属性,用于开发模式下的热更新,确保静态数据不丢失 var allStatic = {}; // 保存所有模块的实例状态,键为模块名称,值为模块实例 var allState = {}; // 事件前缀,用于区分不同模块的事件 var FLAG_PREFIX = 'mtor/'; /** * 保存所有模块依赖注入注册的事件监听器,防止热更新时内存泄漏 * 结构:{ [模块名称]: { [事件名称]: 事件监听函数 } } */ var allEvents = {}; /** * 基于webpack打包构建中定义模块 * @param {string} md -- 模块(必须包含id属性) */ function define(md) { var _a; // @ts-ignore (_a = md.hot) === null || _a === void 0 ? void 0 : _a.accept(); return service(md.id); } exports.define = define; function getPropNames(proto, propNames) { if (propNames === void 0) { propNames = []; } if (!proto || proto === Model.prototype || proto === Object.prototype) { return propNames; } propNames = __spreadArrays(Object.getOwnPropertyNames(proto), propNames); return getPropNames(Object.getPrototypeOf(proto), propNames); } /** * 创建模块 * @param {string} ns -- 模块名称, 模块名称唯一, 不能有冲突 */ function service(ns) { return function (Clazz) { var TYPE = "" + FLAG_PREFIX + ns; var instance = new Clazz(); var __wired = Clazz.prototype.__wired; if (!__wired) { __wired = {}; var tmp_1 = Object.getOwnPropertyDescriptors(instance); Object.keys(tmp_1).forEach(function (key) { if (typeof tmp_1[key].value === "string") { var _ns = tmp_1[key].value.split('xxx$$$~~~')[1]; if (_ns) { __wired[key] = _ns; } } }); } var wiredList = Object.keys(__wired); delete Clazz.prototype.__wired; // 给外面用的原型实例 var prototype = { setData: undefined, reset: undefined, onCreated: undefined, __origin: instance, onBeforeClean: undefined, onBeforeReset: undefined }; // 是否正在同步标志位 var isSyncing = false; var toBeSyncState; // 内部this, 对this 的如何修改都会同步到_toBeSyncState中 var _toBeSyncState; // 真正保存中间数据的对象 // 同步数据方法 var syncFn = function () { if (isSyncing) return; // 节流 Promise.resolve().then(function () { // 重新实例化对象 var newObj = Object.create(allProto[ns]); util_1.assign(newObj, _toBeSyncState); allState[ns] = newObj; EventBus_1.eventBus.emit(TYPE, newObj); isSyncing = false; }); isSyncing = true; }; var propNames = getPropNames(Clazz.prototype); propNames.forEach(function (key) { var _a; if (key !== 'constructor' && typeof Clazz.prototype[key] === 'function') { var evtName_1 = "" + FLAG_PREFIX + ns + "-function-" + key; EventBus_1.eventBus.clean(evtName_1); EventBus_1.eventBus.on(evtName_1, function (_a) { var params = _a.params, cb = _a.cb; var origin = Clazz.prototype[key]; var result = origin.bind(toBeSyncState).apply(void 0, params); cb(result); }); prototype[key] = ((_a = allProto[ns]) === null || _a === void 0 ? void 0 : _a[key]) || function () { var params = []; for (var _i = 0; _i < arguments.length; _i++) { params[_i] = arguments[_i]; } var result; EventBus_1.eventBus.emit(evtName_1, { params: params, cb: function (ret) { result = ret; } }); return result; }; } }); prototype.setData = function (props) { var needUpdate = false; Object.keys(props).forEach(function (key) { if (!Object.getOwnPropertyDescriptor(_toBeSyncState, key)) { Object.defineProperty(toBeSyncState, key, { set: function (value) { if (value !== toBeSyncState[key]) { _toBeSyncState[key] = value; syncFn(); } }, get: function () { return _toBeSyncState[key]; }, }); needUpdate = true; } else if (!needUpdate && props[key] !== _toBeSyncState[key]) { needUpdate = true; } }); if (needUpdate) { // 判断有没有修改 // 重新实例化对象, 同步设置 var newObj = Object.create(allProto[ns]); util_1.assign(_toBeSyncState, props); util_1.assign(newObj, _toBeSyncState); allState[ns] = newObj; EventBus_1.eventBus.emit(TYPE, newObj); } }; var initState = Object.create(prototype); /** * 重置模块数据到初始状态, 一般用于组件销毁的时候调用 */ prototype.reset = function () { EventBus_1.eventBus.emit("" + FLAG_PREFIX + ns + "-reset"); var newObj = Object.create(allProto[ns]); var origin = allProto[ns].__origin; Object.getOwnPropertyNames(origin).forEach(function (key) { newObj[key] = origin[key]; }); wiredList.forEach(function (key) { newObj[key] = allState[__wired[key]]; }); initSyncState(newObj); allState[ns] = newObj; EventBus_1.eventBus.emit(TYPE, newObj); }; prototype.onBeforeReset = function (cb) { if (cb) { EventBus_1.eventBus.once("" + FLAG_PREFIX + ns + "-reset", cb); } }; var finalInstance = allState[ns] || instance; Object.getOwnPropertyNames(instance).forEach(function (key) { initState[key] = finalInstance[key]; }); wiredList.forEach(function (key) { initState[key] = allState[__wired[key]]; }); allEvents[ns] = allEvents[ns] || {}; var events = allEvents[ns]; wiredList.forEach(function (key) { var eventName = "" + FLAG_PREFIX + __wired[key]; events[eventName] && EventBus_1.eventBus.off(eventName, events[eventName]); events[eventName] = function (state) { var _a; util_1.assign(toBeSyncState, (_a = {}, _a[key] = state, _a)); }; EventBus_1.eventBus.on(eventName, events[eventName]); }); var initSyncState = function (state) { if (state === void 0) { state = allState[ns]; } toBeSyncState = Object.create(prototype); _toBeSyncState = __assign({}, state); Object.keys(state).forEach(function (key) { Object.defineProperty(toBeSyncState, key, { set: function (value) { if (value !== toBeSyncState[key]) { _toBeSyncState[key] = value; syncFn(); } }, get: function () { return _toBeSyncState[key]; }, }); }); }; var isHotReload = !!allProto[ns]; if (isHotReload) { // 热更新时候用得到 initSyncState(allState[ns]); util_1.assign(toBeSyncState, initState); syncFn(); // 强制触发一次更新 // assign(Clazz, allStatic[ns]); Promise.resolve().then(function () { Object.keys(allStatic[ns]).forEach(function (key) { Clazz[key] = allStatic[ns][key]; }); allStatic[ns] = Clazz; }); } else { allState[ns] = initState; initSyncState(initState); allStatic[ns] = Clazz; } allProto[ns] = prototype; Clazz.ns = ns; // assign(Clazz.prototype, prototype); // 覆盖初始原型对象 return Clazz; }; } exports.service = service; /** * react hooks 方式获取模块类实例 * @param Class 模块类 */ exports.useModel = function (Class) { var ns = Class.ns; var _a = react_1.useState(allState[ns]), data = _a[0], setData = _a[1]; react_1.useEffect(function () { var eventName = "" + FLAG_PREFIX + ns; EventBus_1.eventBus.on(eventName, setData); return function () { return EventBus_1.eventBus.off(eventName, setData); }; }, []); return data; }; /** * 按照类型自动注入Model实例 * @param {Model} Class --模块类 */ function inject(Class) { var ns = Class.ns; return function (clazz, attr) { if (!clazz) return function () { return "xxx$$$~~~" + ns; }; if (!clazz.__wired) { clazz.__wired = {}; } clazz.__wired[attr] = ns; }; } exports.inject = inject; /** * 按照模块名自动注入Model实例 * @param {string} ns --模块名称 */ function resource(ns) { return function (clazz, attr) { if (!clazz.__wired) { clazz.__wired = {}; } clazz.__wired[attr] = ns; }; } exports.resource = resource; /** * 模块基类,每个模块都应继承该基础模块类 */ var Model = /** @class */ (function () { function Model() { } /** * 批量设置模块数据 * @param {Object} data - key-value 对象 */ Model.prototype.setData = function (data) { return; }; /** * 重置模块数据到初始默认值 */ Model.prototype.reset = function () { return; }; Model.prototype.onBeforeReset = function (cb) { }; Model.ns = ''; return Model; }()); exports.Model = Model; /** * 获取所有模型实例 */ exports.getModels = function () { return allState; }; /** * 用于保存页面销毁前定时器清除方法回调 */ var tempObj = {}; /** * 对useModel 方法二次封装的工具方法, 可以避免开发环境热更新重新调用初始化方法以及重置方法。 * 页面中实例化模块类,同时调用指定初始化方法,以及页面销毁的时候调用 reset方法<br/> * * @param Clazz - 模块类 * * @param initFn - 模块类中方法名字符串或方法回调 * * @param clean - 是否在页面销毁的时候调用reset方法, 默认true */ exports.useInitModel = function (Clazz, initFn, clean) { if (initFn === void 0) { initFn = function () { return null; }; } if (clean === void 0) { clean = true; } var model = exports.useModel(Clazz); react_1.useEffect(function () { if (tempObj[Clazz.ns]) { clearTimeout(tempObj[Clazz.ns]); } else { if (typeof initFn === 'function') { initFn(model); } } return function () { tempObj[Clazz.ns] = setTimeout(function () { clean && model.reset(); delete tempObj[Clazz.ns]; }, 20); }; }, []); return model; }; //# sourceMappingURL=index.js.map