实现简单发布订阅模式

<!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>
</head>

<body>
    <div id="root">
       <div>22</div> 
        {{message}}
    </div>
    <script>
        class Vue {
            constructor(options) {
                // 1.保存数据
                this.options = options;
                this.$el = options.el;
                this.$data = options.data;
                // 2.将data保存到响应式系统中
                new Obsrever(this.$data);
                // 3.代理this.$data的数据
                Object.keys(this.$data).forEach(key => {
                    this._proxy(key)
                })
                // 4.处理$el
                new Compiler(this.$el, this);
            }
            _proxy(key) {
                Object.defineProperty(this, key, {
                    get() { //代理
                        return this.$data[key];
                    },
                    set(newValue) {
                        this.$data[key] = newValue;
                    }
                })
            }
        }
        // 观察者
        class Obsrever {
            constructor(data) {
                this.data = data;
                Object.keys(data).forEach(key => {
                    // 一个属性key对应一个发布者Dep
                    this.defineReactive(this.data, key, this.data[key]);
                })
            }
            defineReactive(data, key, value) {
                const dep = new Dep();
                // may have problems 
                Object.defineProperty(data, key, {
                    // 订阅谁在界面使用了那些属性
                    get() {
                        if (Dep.target) {
                            dep.addSub(Dep.target);
                        }
                        return value;
                        // return data[key];  //这里代码会不断递归报错
                    },
                    set(newValue) {
                        if (value === newValue) return false;
                        data[key] = newValue;
                        // 通知notify所有订阅者更新自己的视图
                        dep.notify();
                    }
                })
            }
        }
        // 发布者
        class Dep {
            constructor() {
                this.subs = [];
            }
            addSub(watcher) {
                this.subs.push(watcher);
            }
            notify() {
                this.subs.forEach(item => {
                    item.update();
                })
            }
        }
        // 订阅者
        class Watcher {
            constructor(node, key, vm) {
                this.node = node;
                this.name = key;
                this.vm = vm;
                Dep.target = this;
                this.update();
                Dep.target = null;
            }
            update() {
                this.node.nodeValue = this.vm[this.name];
            }
        }

        let regExp = /\{\{(.+?)\}\}/g;
        class Compiler {
            // 这里的vm是Vue实例对象,不是虚拟DOM
            constructor(el, vm) {
                this.el = document.querySelector(el);
                this.vm = vm;
                this.frag = this._createFragment();
                this.el.appendChild(this.frag);
            }
            _createFragment() {
                const frag = document.createDocumentFragment();
                var child;
                while (child = this.el.firstChild) {
                    this._compile(child);
                    frag.appendChild(child);
                }
                return frag;
            }
            _compile(node) {
                if (node.nodeType == 3) {  //文本节点
                    if (regExp.test(node.nodeValue)) {
                        const name = RegExp.$1.trim();
                        new Watcher(node, name, this.vm);
                    } 
                }else if(node.nodeType==1) {  //元素节点
                    
                }
            }
        }


        var app = new Vue({
            el: '#root',
            data: {
                message: 'msg'
            }
        })
    </script>
</body>

</html>

响应式

<script>
        var obj = {
            message: 'msg'
        }

        Object.keys(obj).forEach(key => {
            var value = obj[key];  //原来的值
            Object.defineProperty(obj, key, {
                set(newValue) {  //新值
                    console.log('setter value:' + value)
                    value = newValue;
                    console.log('setter value:' + value)
                }
                , get() {
                    console.log('getter value:' + value)
                    return value;
                }
            })
        })

        // 发布者
        class Dep {
            constructor() {
                this.subs = [];
            }
            addSub(watcher) {
                this.subs.push(watcher);
            }
            notify() {
                this.subs.forEach(item => {
                    item.update();
                })
            }
        }
        // 订阅者
        class watcher {
            constructor(name) {
                this.name = name;
            }
            update() {
                console.log(this.name + 'is update')
            }
        }
        var dep = new Dep();
        const w1 = new watcher('comp1');
        const w2 = new watcher('comp2');
        const w3 = new watcher('comp3');
        dep.subs.push(w1, w2, w3);
        dep.notify();
    </script>
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值