vue动态数据绑定3--深层次数据变化逐层往上传播

基于vue动态数据绑定2,再多考虑一个问题:”深层次数据变化如何逐层往上传播”。举个例子。

let app = new Observer({
    name: {
        first: 'yy',
        last: 'jm'
    },
    age: 18
});

app2.$watch('name', function (newName) {
    console.log('你的姓名发生了变化')
});

app.data.name.firstName = 'hahaha';
// 输出:你的姓名发生了变化。

为了实现深层次数据变化的向上传播,需要得到被改变的数据的父级并触发相应的回调函数,然后再逐级向上触发每一层级的回调函数。实现代码如下:

<script>
function Observer(data, events, parent, parentKey){
    this.data = data;
    this.events = events || {};
    this.parent = parent || {};
    this.parentKey = parentKey || '';
    this.walk(data, this.events);
}
Observer.prototype.walk = function(data, events) {
    for(var key in data) {
        if(data.hasOwnProperty(key)){
            if(typeof(data[key]) == 'object'){
                new Observer(data[key], events, this, key)
            };
            this.convert(key, data[key], events);
        }
    }
}
Observer.prototype.convert = function(key, val, events) {
    var self = this;
    Object.defineProperty(this.data, key, {
        enumerable: true,
        configurable: true,
        get: function() {
            console.log('你访问了' + key);
            return val;
        },
        set: function(newVal) {
            console.log('你设置了', key, ',新的值为', newVal);
            if (newVal !== val) {
                val = newVal;
                // 保存key的上级,如果有的话
                var parent = self.parent;
                // 保存key的上级的key值
                var parentKey = self.parentKey;
                // 循环寻找上级触发事件
                while (parent) {
                  self.$emit(parentKey, newVal);
                  parentKey = parent.parentKey;
                  parent = parent.parent;
                }
                //触发当前key事件
                self.$emit(key, newVal); 
            }
            // 如果这个newVal是obj,继续递归调用new Observer
            if (typeof newVal === "object") {
                return new Observer(newVal, events, this, key);
            }
        }
    })
}

Observer.prototype.$watch = function(key, listener) {
    if(!this.events[key]){
        this.events[key] = [];
    };
    this.events[key].push(listener);
}

Observer.prototype.$emit = function() {
    var key = [].shift.call(arguments);
    var data = [].slice.call(arguments);
    if(!this.events[key] || this.events[key].length < 1) return;
    this.events[key].forEach(function(listener){
        listener(data || {})
    })
}
var data = {
    user: {
        name: {
            first: {
                y: "y"
            },
            last: "jm"
        },
        age: 18
    },
    address: "成都"
}

let app = new Observer(data);

app.$watch('user', function() {
    console.log('你改变了user');
});
app.$watch('name', function(){
    console.log('你改变了name');
});
app.$watch('first', function(){
    console.log('你改变了first');
});
app.$watch('y', function(y){
    console.log(`你改变了y, 现在是${y}`);
});
app.$watch('age', function(age){
    console.log(`你的age改变了,现在是${age}`);
});
app.$watch('address', function(address){
    console.log(`你的address改变了,现在是${address}`);
});
app.data.user.age = 20;
script>

在vue数据绑定2的基础上,增加了this.parent、提示。parentKey用于得到相应元素的上级,然后再得到上级的上级… 。
效果如下:

你可能感兴趣的:(vue)