关于javascript:手写vue3-观察者模式mini版

30次阅读

共计 1477 个字符,预计需要花费 4 分钟才能阅读完成。

将以下代码保留为文件 即可查看成果!


<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>

正文完
 0