手写vue3 观察者模式mini版

灬都是个谜

将以下代码保存为文件 即可查看效果!


<script type="text/javascript">
    const weakMap = new WeakMap
    const effectStack = []
    let activeEffect
    
    function pushStack(o) { effectStack.push(o); activeEffect = o }
    function popStack() { effectStack.pop(); activeEffect = effectStack[effectStack.length - 1] }
    
    function trigger(obj, k) {
        let k2depMap = weakMap.get(obj)
        if (!k2depMap) return
        const dep = k2depMap[k]
        if (!dep) return
        dep.forEach(e => e())
    }
    
    function track(obj, k) {
        if (!activeEffect) return
        let k2depMap = weakMap.get(obj)
        if (!k2depMap) weakMap.set(obj, k2depMap = {})
        let dep = k2depMap[k]
        if (!dep) dep = k2depMap[k] = new Set
        dep.add(activeEffect)
    }
    
    function effect(fn, option = {}) {
        const effect = function() {
            try {
                pushStack(fn)
                return fn()
            } finally {
                popStack()
            }
        }
        if (!option.lazy) effect()
        return effect
    }
    
    function reactive(state) {
        return new Proxy(state, {
            set(target, k, v) {
                target[k] = v
                trigger(target, k, v)
            },
            get(target, k) {
                track(target, k)
                return target[k]
            }
        })
    }
</script>

<button id="btn" onclick="btn_click()"></button>
<div id="circle" onclick="circle_click()">切换圆角</div>

<script type="text/javascript">
    const state = reactive({ count: 1, circle: true })
    effect(() => {
        const div = document.getElementById('btn')
        div.innerText = '计数 _ ' + state.count
    })
    effect(() => {
        const div = document.getElementById('circle')
        const style = {
            borderRadius: state.circle ? '20px' : 0
        }
        Object.assign(div.style, style)
    })
    
    function btn_click() {
        state.count++
    }
    function circle_click() {
        state.circle = !state.circle
    }
</script>

<style type="text/css">
    #circle {
        display: flex;
        justify-content: center;
        align-items: center;
        margin-top: 10px;
        width: 100px;
        height: 100px;
        background-color: #dd8538;
    }
</style>
阅读 203
0 声望
0 粉丝
0 条评论
你知道吗?

0 声望
0 粉丝
宣传栏