UNPKG

mtor-vue

Version:

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

385 lines 14.5 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 __spreadArray = (this && this.__spreadArray) || function (to, from, pack) { if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) { if (ar || !(i in from)) { if (!ar) ar = Array.prototype.slice.call(from, 0, i); ar[i] = from[i]; } } return to.concat(ar || Array.prototype.slice.call(from)); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.useInitModel = exports.getModels = exports.Model = exports.inject = exports.useModel = exports.service = exports.define = exports.evtBus = void 0; /** * mtor-vue * Copyright (c) 2021 Sampson Li (lichun) <740056710@qq.com> * @license MIT */ // @ts-ignore var vue_1 = require("vue"); var util_1 = require("./util"); var EventBus_1 = require("./EventBus"); // declare const Promise; var EventBus_2 = require("./EventBus"); Object.defineProperty(exports, "evtBus", { enumerable: true, get: function () { return EventBus_2.eventBus; } }); // 保存所有模块的原型 var allProto = {}; // 保存所有模块的static属性, 方便开发模式热更新静态数据保留 var allStatic = {}; var allState = {}; var FLAG_PREFIX = 'mtor/'; // 用于保存所有模块依赖注入注册的事件, 防止热更新的时候内存泄露 var allEvents = {}; var isHotReload = false; /** * 定义模块 * @param {string} md -- 模块(必须包含id属性) */ function define(md) { var _a; // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore (_a = md.hot) === null || _a === void 0 ? void 0 : _a.accept(); return service(md.id); } exports.define = define; /** * 创建模块 * @param {string} ns -- 模块名称, 模块名称唯一, 不能有冲突 */ function service(ns) { return function (Clazz) { var TYPE = "".concat(FLAG_PREFIX).concat(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, onBeforeReset: undefined, onBeforeClean: 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]); (0, util_1.assign)(newObj, _toBeSyncState); allState[ns] = newObj; EventBus_1.eventBus.emit(TYPE, newObj); isSyncing = false; }); isSyncing = true; }; var propNames = Object.getOwnPropertyNames(Clazz.prototype); if (Object.getPrototypeOf(Clazz.prototype) !== Model.prototype) { propNames = __spreadArray(__spreadArray([], Object.getOwnPropertyNames(Object.getPrototypeOf(Clazz.prototype)), true), propNames, true); } propNames.forEach(function (key) { var _a; if (key !== 'constructor' && typeof Clazz.prototype[key] === 'function') { var evtName_1 = "".concat(FLAG_PREFIX).concat(ns, "-function-").concat(key); EventBus_1.eventBus.clean(evtName_1); // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore 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); }); // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore 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]); (0, util_1.assign)(_toBeSyncState, props); (0, util_1.assign)(newObj, _toBeSyncState); allState[ns] = newObj; EventBus_1.eventBus.emit(TYPE, newObj); } }; var initState = Object.create(prototype); /** * 重置模块数据到初始状态, 一般用于组件销毁的时候调用 */ prototype.reset = function () { if (typeof prototype.onBeforeClean === 'function') { // 清空数据前钩子函数 // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore prototype.onBeforeClean(); } EventBus_1.eventBus.emit("".concat(FLAG_PREFIX).concat(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("".concat(FLAG_PREFIX).concat(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]]; }); // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore allEvents[ns] = allEvents[ns] || {}; // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore var events = allEvents[ns]; wiredList.forEach(function (key) { var eventName = "".concat(FLAG_PREFIX).concat(__wired[key]); events[eventName] && EventBus_1.eventBus.off(eventName, events[eventName]); events[eventName] = function (state) { var _a; (0, 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]; }, }); }); }; isHotReload = !!allProto[ns]; if (isHotReload) { // 热更新时候用得到 initSyncState(allState[ns]); // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore (0, util_1.assign)(toBeSyncState, initState); syncFn(); // 强制触发一次更新 (0, util_1.assign)(Clazz, allStatic[ns]); } else { allState[ns] = initState; initSyncState(initState); allStatic[ns] = (0, util_1.assign)({}, Clazz); } allProto[ns] = prototype; // 初始化提供created 方法调用, 热更新不重复调用 if (typeof prototype.onCreated === 'function' && !isHotReload) { prototype.onCreated(); } Clazz.ns = ns; // assign(Clazz.prototype, prototype); // 覆盖初始原型对象 return Clazz; }; } exports.service = service; /** * react hooks 方式获取模块类实例 * @param Class 模块类 */ var useModel = function (Class) { var ns = Class.ns; var target = Object.create(allProto[ns]); (0, util_1.assign)(target, allState[ns]); var model = (0, vue_1.shallowReactive)(target); var eventName = "".concat(FLAG_PREFIX).concat(ns); var flag = true; // 避免重复调用watch逻辑 var setModel = function (md) { if (isHotReload && Object.getPrototypeOf(target) !== allProto[ns]) { // 如果是开发环境热更新, 同步最新方法到模型对象中 //@ts-ignore model.__proto__ = allProto[ns]; } (0, util_1.assign)(model, md); flag = false; }; EventBus_1.eventBus.on(eventName, setModel); var cancelWatch = (0, vue_1.watch)(model, function (newObj) { if (flag) { target.setData(newObj); } flag = true; }, { deep: false }); (0, vue_1.onBeforeUnmount)(function () { EventBus_1.eventBus.off(eventName, setModel); cancelWatch(); }); return model; }; exports.useModel = useModel; /** * 按照类型自动注入Model实例 * @param {Model} Class --模块类 */ function inject(Class) { var ns = Class.ns; return function (clazz, attr) { if (!clazz) return function () { return "xxx$$$~~~".concat(ns); }; if (!clazz.__wired) { clazz.__wired = {}; } clazz.__wired[attr] = ns; }; } exports.inject = inject; /** * 模块基类,每个模块都应继承该基础模块类 */ var Model = exports.Model = /** @class */ (function () { function Model() { } /** * 批量设置模块数据 * @param data - key-value 对象 */ // eslint-disable-next-line @typescript-eslint/ban-types Model.prototype.setData = function (data) { return; }; /** * 重置模块数据到初始默认值 */ Model.prototype.reset = function () { return; }; /** * 注册模块reset前调用方法, 可多次调用 * @param cb 模块数据被reset前调用回调方法 */ Model.prototype.onBeforeReset = function (cb) { return; }; Model.ns = ''; return Model; }()); /** * 获取所有模型实例 */ var getModels = function () { return allState; }; exports.getModels = getModels; /** * 用于保存页面销毁前定时器清除方法回调 */ var tempObj = {}; /** * 对useModel 方法二次封装的工具方法, 可以避免开发环境热更新重新调用初始化方法以及重置方法。 * 页面中实例化模块类,同时调用指定初始化方法,以及页面销毁的时候调用 reset方法<br/> * * @param Clazz - 模块类 * * @param initFn - 模块类中方法名字符串或方法回调 * * @param clean - 是否在页面销毁的时候调用reset方法, 默认true */ var useInitModel = function (Clazz, initFn, clean) { if (initFn === void 0) { initFn = function () { return null; }; } if (clean === void 0) { clean = true; } var model = (0, exports.useModel)(Clazz); if (tempObj[Clazz.ns]) { clearTimeout(tempObj[Clazz.ns]); } else { if (typeof initFn === 'function') { (0, vue_1.onMounted)(function () { initFn(model); }); } } (0, vue_1.onBeforeUnmount)(function () { tempObj[Clazz.ns] = setTimeout(function () { //@ts-ignore clean && model.reset(); delete tempObj[Clazz.ns]; }, 20); }); return model; }; exports.useInitModel = useInitModel; //# sourceMappingURL=index.js.map