模拟vue2模板编译与双向绑定

html部分

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="./vue.js"></script>
</head>

<body>
    <div id="app">
        <span>阿婆主:{{name}}</span>
        <input type="text" v-model="name">
        <span>更多:{{more.like}}</span>
        <input type="text" v-model="more.like">
    </div>
</body>
<script>
    const vm = new Vue({
        el: "#app",
        data: {
            name: "走我们钓鱼去",
            more: {
                like: "升职加薪"
            }
        }
    })
    console.log(vm);
</script>

</html>

vue.js

class Vue {
    constructor(obj_instance) {
        this.$data = obj_instance.data;
        Observer(this.$data)
        Compile(obj_instance.el, this)
    }
}
// 数据监听
function Observer(data_instance) {
    if (data_instance && typeof data_instance !== 'object') return
    const dependency = new Dependency();
    Object.keys(data_instance).forEach(key => {
        let value = data_instance[key]
        Observer(value)
        Object.defineProperty(data_instance, key, {
            enumerable: true,
            configurable: true,
            get() {
                Dependency.temp && dependency.addSub(Dependency.temp)
                return value
            },
            set(newValue) {
                value = newValue
                Observer(newValue)
                value = newValue
                dependency.notify()
            }
        })
    })
}
// 模板解析
function Compile(el, vm) {
    vm.$el = document.querySelector(el)
    const fragment = document.createDocumentFragment()
    let child
    while (child = vm.$el.firstChild) {
        fragment.append(child)
    }
    fragment_complie(fragment)
    // 替换文档碎片
    function fragment_complie(node) {
        const pattern = /\{\{\s*(\S+)\s*\}\}/
        if (node.nodeType === 3) {
            const xxx = node.nodeValue
            const result_regex = pattern.exec(node.nodeValue)
            if (result_regex) {
                const arr = result_regex[1].split(".")
                const value = arr.reduce((total, current) => total[current], vm.$data)
                node.nodeValue = xxx.replace(pattern, value)
                // 创建订阅者
                new Watcher(vm, result_regex[1], newValue => {
                    node.nodeValue = xxx.replace(pattern, newValue)
                })
            }
            return
        }
        if (node.nodeType === 1 && node.nodeName === 'INPUT') {
            const attr = Array.from(node.attributes)
            attr.forEach(i => {
                if (i.nodeName === 'v-model') {
                    const value = i.nodeValue.split('.').reduce(
                        (total, current) => total[current], vm.$data
                    )
                    node.value = value
                    new Watcher(vm, i.nodeValue, newValue => {
                        node.value = newValue
                    })
                    node.addEventListener("input", e => {
                        const arr1 = i.nodeValue.split('.')
                        const arr2 = arr1.slice(0, arr1.length - 1)
                        const final = arr2.reduce(
                            (total, current) => total[current], vm.$data
                        )
                        final[arr1[arr1.length - 1]] = e.target.value
                    })
                }
            })
        }
        node.childNodes.forEach(child => fragment_complie(child))
    }
    vm.$el.appendChild(fragment)
}

// 依赖-收集和通知订阅者
class Dependency {
    constructor() {
        this.subscribers = []
    }
    addSub(sub) {
        this.subscribers.push(sub)
    }
    notify() {
        this.subscribers.forEach(sub => sub.update())
    }
}

// 订阅者
class Watcher {
    constructor(vm, key, callback) {
        this.vm = vm
        this.key = key
        this.callback = callback
        Dependency.temp = this
        key.split(".").reduce((total, current) => total[current], vm.$data)
        Dependency.temp = null;
    }
    update() {
        const value = this.key.split('.').reduce(
            (total, current) => total[current], this.vm.$data
        )
        this.callback(value)
    }
}
posted @   走我们钓鱼去  阅读(33)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示