MVVM数据双向绑定Vue数据劫持

3 篇文章 0 订阅
1 篇文章 0 订阅

mvvm只关心数据的变化,无需直接操作dom节点,以下是一个简易的双向绑定原理的例子,可复制粘贴运行测试

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div id="test">{{name}}</div>
<script>
//观察函数,递归观察data的所有属性,数据变化时利用set和get订阅和发布消息
    function observe(obj) {
        // 判断类型
        if (!obj || typeof obj !== 'object') {
            return
        }
        Object.keys(obj).forEach(key => {
            defineReactive(obj, key, obj[key])
        })
    }

    function defineReactive(obj, key, val) {
        // 递归子属性
        observe(val)
        let dp = new Dep()
        Object.defineProperty(obj, key, {
            enumerable: true,
            configurable: true,
            get: function reactiveGetter() {
                console.log('get value')
                // 如果这个属性实例化了一个监听对象Watcher,将 Watcher 添加到订阅
                if (Dep.target) {
                    dp.addSub(Dep.target)
                }
                return val
            },
            set: function reactiveSetter(newVal) {
                console.log('change value')
                val = newVal
                // 执行 watcher 的 update 方法
                dp.notify()
            }
        })
    }
	//我的理解相当于一个eventBus,可实例为一个订阅发布对象,用于订阅和发布消息
    class Dep {
        constructor() {
            this.subs = []
        }

        addSub(sub) {
            // sub 是 Watcher 实例
            this.subs.push(sub)
        }

        notify() {
            this.subs.forEach(sub => {
                sub.update()
            })
        }
    }

    // 全局属性,通过该属性配置 Watcher
    Dep.target = null

    function update(value) {
        // document.querySelector('span').innerText = value
        console.log('span', document.getElementById('test'))
        document.getElementById('test').innerHTML = value
    }
// 监听类,用于监听data数据
    class Watcher {
    
        constructor(obj, key, cb) {
            // 将 Dep.target 指向自己
            // 然后触发属性的 getter 添加监听
            // 最后将 Dep.target 置空
            Dep.target = this
            this.cb = cb//更新dom的函数
            this.obj = obj//监听的data数据
            this.key = key//监听的data数据中的某一属性的key
            this.value = obj[key]//监听的data数据中的某一属性的值
            Dep.target = null
        }

        update() {
            // 获得新值
            this.value = this.obj[this.key]
            // 调用 update 方法更新 Dom
            this.cb(this.value)
        }
    }

    var data = {name: 'yck'}
    observe(data)
    // 测试实例化一个监听类,监听某一个属性变化,若属性变化则更新模板显示
    new Watcher(data, 'name', update)
    // 手动触发属性值变化
    data.name = 'yyy'

</script>
<style>
</style>
</body>
</html>

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值