Files
2025-05-18 07:42:27 +00:00

335 lines
10 KiB
JavaScript
Executable File

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);
});