You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
OneAuth/oaer/lib/components/proxy.ts

145 lines
3.6 KiB
TypeScript

1 month ago
/*
* proxy.ts
* Copyright (C) 2024 veypi <i@veypi.com>
* 2024-10-23 17:20
* Distributed under terms of the GPL license.
*/
type voidFn = () => void
const callbackCache: (voidFn | undefined)[] = []
const cacheUpdateList: number[] = []
// 界面更新响应频率40hz
setInterval(() => {
let list = new Set(cacheUpdateList.splice(0))
for (let l of list) {
if (callbackCache[l]) {
callbackCache[l]()
}
}
}, 25)
// 绑定事件删除
setInterval(() => {
let exists = new Set()
let check = (dom: Element) => {
let ids = dom.getAttribute('vbind-fns')?.split(',')
if (ids?.length) {
for (let i of ids) {
exists.add(i)
}
}
for (let child of dom.children) {
check(child)
}
}
check(document.body)
for (let i in callbackCache) {
if (!exists.has(i)) {
// 只删除元素,保留位置
delete callbackCache[i]
// console.log('remove ' + i)
}
}
}, 1000)
1 month ago
function generateUniqueId() {
const timestamp = performance.now().toString(36);
const random = Math.random().toString(36).substring(2, 5);
return `${timestamp}-${random}`;
}
1 month ago
function ForceUpdate() {
for (let c of callbackCache) {
if (c) {
c()
}
1 month ago
}
}
var listen_tags: number[] = []
function Listen(callback: voidFn): number {
let idx = callbackCache.length
listen_tags.push(idx)
1 month ago
callbackCache.push(callback)
callback()
listen_tags.pop()
return idx
1 month ago
}
const isProxy = Symbol("isProxy")
const DataID = Symbol("DataID")
1 month ago
function Watch<T extends Object>(data: T) {
const did = generateUniqueId()
let isArray = false
if (Object.prototype.toString.call(data) === '[object Array]') {
isArray = true
}
// console.log(`watch ${did} ${isArray}`, data)
const listeners: { [key: string | symbol]: number[] } = {}
1 month ago
const handler = {
get(target: Object, key: string | symbol, receiver: any) {
if (key === isProxy) {
return true
}
if (key === DataID) {
return did
}
const value = Reflect.get(target, key, receiver)
1 month ago
if (typeof value === 'object' && value !== null) {
if (value[isProxy]) {
return value
} else {
let newValue = Watch(value)
Reflect.set(target, key, newValue, receiver)
return newValue
}
1 month ago
}
let idx = -1
if (listen_tags.length > 0) {
let lkey = key
idx = listen_tags[listen_tags.length - 1]
if (isArray) {
lkey = ''
}
if (!listeners[lkey]) {
listeners[lkey] = [idx]
} else if (listeners[lkey].indexOf(idx) == -1) {
listeners[lkey].push(idx)
1 month ago
}
}
// console.log(`${did} get ${key.toString()}:${value} ${idx}`)
1 month ago
return value;
},
set(target: Object, key: string | symbol, newValue: any, receiver: any) {
// console.log(`${did} set ${key.toString()} ${newValue}`)
1 month ago
const result = Reflect.set(target, key, newValue, receiver);
if (result) {
let lkey = key
if (isArray) {
lkey = ''
}
if (listeners[lkey]) {
for (let cb of listeners[lkey]) {
cacheUpdateList.push(cb)
1 month ago
}
}
}
return result;
},
deleteProperty(target: Object, key: string) {
// console.log(`del ${key}`)
1 month ago
const result = Reflect.deleteProperty(target, key);
if (result) {
}
return result
}
};
let res = new Proxy<T>(data, handler);
// Symbol(Symbol.toStringTag)
// res[Symbol.toStringTag] = 'Proxy'
return res
1 month ago
}
export default { Watch, Listen, ForceUpdate, DataID, generateUniqueId }