JavaScript 数据与DOM双向绑定

reactive.js

export default { reactive }

export function reactive(target, prism = new Map()) {
    if (Array.isArray(target)) {
        const items = target.map(item => {
            if (item instanceof HTMLElement) {
                return item
            }
            return reactive(item, prism)
        })
        return new Proxy(items, {
            get(target, prop) {
                if (prop === "map") {
                    return function (...args) {
                        return reactive(target[prop](...args).map((item, index) => {
                            if (item === target[index]) {
                                return item
                            }
                            if (item instanceof HTMLElement) {
                                const arr = prism.get(target[index]) ?? []
                                arr.push(item)
                                prism.set(target[index], arr)
                                return item
                            }
                            return reactive(item, prism)
                        }))
                    }
                }
                if (prop === "pop") {
                    console.log("调用了 pop 方法", target)
                    return function (...args) {
                        const item = target[prop](...args)
                        const arr = prism.get(item) ?? []
                        arr.forEach(element => element.remove()) // 移除映射的DOM
                        return item
                    }
                }
                if (prop === "splice") {
                    console.log("调用了 splice 方法", target)
                    return function (...args) {
                        const items = target[prop](...args)
                        items.map(item => {
                            const arr = prism.get(item) ?? []
                            arr.forEach(element => element.remove()) // 移除映射的DOM
                        })
                        return items
                    }
                }
                return target[prop]
            },
            set(target, prop, value) {
                target[prop] = reactive(value, prism)
                return true
            }
        })
    }

    if (typeof target === "object" && target !== null) {
        const proxiedObject = {}
        for (const key in target) {
            proxiedObject[key] = reactive(target[key], prism)
        }

        return new Proxy(proxiedObject, {
            get(target, prop) {
                return target[prop]
            },
            set(target, prop, value) {
                target[prop] = value
                return true
            }
        })
    }

    return target
}

index.html

<!DOCTYPE html>
<script type="module">
// 创建响应式数据
const data = reactive([
    { id: 1, name: 'aa' },
    { id: 2, name: 'bb' },
    { id: 3, name: 'cc' },
])

document.body.append(data.map(item => {
    const element = document.createElement('div')
    element.textContent = item.name
    element.onclick = (event) => {
        console.log('删除数据会自动移除DOM元素')
        data.splice(data.indexOf(item), 1)
    }
    return element
}))

</script>

--- satori ---

Last