layui.define([], function (exports) { const MOD_NAME = "react"; // 监听数据,后面可以用一个WeakMap + 存放key的数组替换 let proxyData = { data: [], // 数据 methods: [], // 方法 hooks: [], // 钩子 }; let react = { /** * @abstract 通知并执行钩子函数 * * @param {String} hook 监听的变量名 * @param {'pre'|'post'} type 类型 * @param {...any} args */ notifyHooks: (hook, type = 'pre', ...args) => { for (const f of proxyData.hooks.filter(v => { return v.target === hook && v.type === type; })) { f.handler(args); } }, /** * @abstract 注册一些钩子,当托管变量发生改变时触发 * * 注册钩子: * @example * ```javascript * // 注册托管变量 * laytp.react.regData({ * hello: 0, * world: 2 * }); * * // 注册钩子 * laytp.react.regHooks({ * // 监听名为hello的变量改变 * hello: () => { * console.log('Here!'); * }, * * world: { * type: 'post', // 默认都为'pre',为变量修改前回调,'post'为变量修改后回调 * handler: (target, prop, data) => { * data.value = 50; * } * } * }); * ``` * * 调用: * @example * ```javascript * laytp.data.hello = 10; * // laytp.data.hello -> 10 * * laytp.data.world = 20; * // laytp.data.world -> 50 * ``` * * @param {Object} obj 需注册的钩子的Object * @returns */ regHooks: function (obj) { if (typeof obj !== 'function' && typeof obj !== 'object') { console.error('请传入钩子对象或一个具名函数'); return; } if (typeof obj === 'function') { if (obj.name === '') { console.error('不支持传入闭包'); return; } proxyData.hooks.push({ target: obj.name, type: 'pre', handler: obj }); return; } for (const key in obj) { if (Object.hasOwnProperty.call(obj, key)) { const func = obj[key]; if (typeof func === 'object' && typeof func.type === 'string' && typeof func.handler === 'function') proxyData.hooks.push({ target: key, type: func.type, handler: func.handler }); else if (typeof func === 'function') proxyData.hooks.push({ target: key, type: 'pre', handler: func }); else console.warn(`${key} 不是一个合法的钩子`); } } }, /** * @abstract 注册一些托管方法 * * 注册: * @example * ```javascript * laytp.react.regMethods({ * alert() { * alert('warning'); * } * }); * ``` * * 调用: * @example * ```javascript * laytp.methods.alert(); * ``` * * @param {Object} obj 需注册的方法的Object * @returns */ regMethods: function (obj) { if (typeof obj === 'function') { if (obj.name === '') { console.error('不支持传入闭包'); return; } if (proxyData.methods.findIndex(v => { return v.key === key; }) > -1) { proxyData.methods.find(v => { return v.key === key }).handler = func; return; } proxyData.methods.push({ key: obj.name, handler: func }); Object.defineProperty(laytp.methods, `${obj.name}`, { get() { let q = proxyData.methods.find(v => { return v.key === obj.name; }); return q === undefined ? undefined : q.handler; } }); return; } for (const key in obj) { if (Object.hasOwnProperty.call(obj, key)) { const func = obj[key]; if (typeof func !== 'function') { console.warn(`${key} 不是一个合法的函数`); continue; } if (proxyData.methods.findIndex(v => { return v.key === key; }) > -1) { proxyData.methods.find(v => { return v.key === key }).handler = func; continue; } proxyData.methods.push({ key, handler: func }); Object.defineProperty(react.methods, `${key}`, { get() { let q = proxyData.methods.find(v => { return v.key === key; }); return q === undefined ? undefined : q.handler; } }); } } }, /** * @abstract 注册一些托管数据,当托管数据发生变化时调用同名钩子函数,暂不支持深度监听 * * 注册: * @example * ```javascript * laytp.react.regData({ * some: 1, * other: 10, * meow: "I'm hungry" * }); * ``` * * 调用: * @example * ```javascript * laytp.data.some = 10; * laytp.data.other = 'Ok'; * ``` * * @param {Object} obj 需注册的数据的Object * @returns */ regData: function (obj) { if (typeof obj !== 'object') { console.error('请传入数据对象'); return; } const handler = { setByOutside(hooks, target, prop, value) { for (const h of hooks) { let data = { get value() { return value; }, set value(v) { value = v; } }; h.handler(target, prop, data); target[prop] = value; } }, set(target, prop, value) { // 写入前钩子 try { handler.setByOutside(proxyData.hooks.filter(o => { return o.target === target.key && o.type === 'pre'; }), target, prop, value); } catch (error) { console.error(error); return; } // 写入 target[prop] = value; // 写入后钩子 try { handler.setByOutside(proxyData.hooks.filter(o => { return o.target === target.key && o.type === 'post'; }), target, prop, value); } catch (error) { console.error(error); } }, get(target, prop) { return target[prop]; } }; for (const key in obj) { if (Object.hasOwnProperty.call(obj, key)) { const element = obj[key]; if (proxyData.data.findIndex(v => { return v.key === key }) > -1) { proxyData.data.find(v => { return v.key === key }).value = element; continue; } proxyData.data.push(new Proxy({ key, value: element }, handler)); Object.defineProperty(react.data, `${key}`, { get() { let q = proxyData.data.find(v => { return v.key === key; }); return q === undefined ? undefined : q.value; }, set(v) { let q = proxyData.data.find(v => { return v.key === key; }); (q) && (q.value = v); } }); } } }, data: new Proxy({}, { set(target, p, newVal) { react.regData({ [p]: newVal }); }, get(target, p) { return target[p]; } }), methods: new Proxy({}, { set(target, p, newVal) { react.regMethods({ [p]: newVal }); }, get(target, p) { return target[p]; } }), hooks: new Proxy({}, { set(target, p, newVal) { react.regHooks({ [p]: newVal }); }, get(target, p) { return target[p]; } }) }; //输出模块 exports(MOD_NAME, react); });