vue设计模式利用object.defineProperty解决数据劫持

120 阅读1分钟

理念:

1、将所有data数据交给object.defineProperty进行set个get监听

2、初始化vue对象的时候,需要将对应的data,el赋值给当前的this对象

3、对html关联的el对象进行监听,对于v-model属性进行input监听,如果有输入就添加watch对象

3、对html关联的el对象进行监听,对于v-text属性进行innnerHtml监听,如果有输入就添加watch对象

4、创建watch对象,查看是否有数据更新

            constructor(options) {
                this.options = options
                this.$data = options.data()
                this.__watchers = {}
                // 创建观察者
                this.Observer(this.$data)


            }
            mount (el) {
                this.$el = document.querySelector(el)
                // 进行模版监听
                this.Compire(this.$el)
            }
            Observer (data) {
                for (const key in data) {
                    this.__watchers[key] = []
                    if (Object.hasOwnProperty.call(data, key)) {
                        // 获取到data对应的值
                        let element = data[key];
                        const watch = this.__watchers[key]
                        Object.defineProperty(this.$data, key, {
                            set: function (newVal) {
                                if (newVal !== element) {
                                    element = newVal
                                }
                                // 通知他的观察者去更新数据
                                console.log(watch.length)
                                watch.forEach(watcher => {
                                    watcher.update()
                                });
                            },
                            get: function () {
                                return element
                            }
                        })

                    }
                }
            }
            Compire (el) {
                let nodes = el.children
                for (let index = 0; index < nodes.length; index++) {
                    const node = nodes[index];
                    if (node.hasAttribute('v-model')) {
                        let attr = node.getAttribute('v-model')
                        console.log(attr)
                        console.log(this.__watchers[attr])
                        this.__watchers[attr].push(new Watch(node, this, attr, 'value'))
                        node.addEventListener('input', () => {
                            this.$data[attr] = node.value
                        })
                    }
                    if (node.hasAttribute('v-text')) {
                        let attr = node.getAttribute('v-text')
                        this.__watchers[attr].push(new Watch(node, this, attr, 'innerHTML'))
                    }

                }

            }
        }
        class Watch {
            constructor(el, vue, exp, att) {
                this.el = el
                this.vue = vue
                this.exp = exp
                this.att = att
                // this.update();
            }
            update () {
                console.log(this,'this.vue.$data[this.exp]',this.vue.$data[this.exp])
                console.log(this.el[this.att],'1111444565445')
                console.log(this.att,"this.attthis.attthis.att")
                this.el[this.att] = this.vue.$data[this.exp]
            }
        }
        const app = new Vue({
            data () {
                return {
                    name: '',
                    age: ''
                }
            }
        })
        console.log('vue对象:', app)
        // 初始化vue对象的元素
        app.mount('#app')