实现一个简单的类 Vue 框架(二) —— 数据的绑定之修改可监听的数据绑定方法

Vue是MVVM框架,也就是M(数据)的变化能够驱动V(模板)的变化,所以数据修改可响应的实现是一个关键点。实现数据变化可响应的方法很多,事件驱动,广播,订阅等方法,而Vue使用的是js的原生API  Object.defineProperty。这种实现方法的优点是:实现简单。缺点是:只能兼容到IE9以上。

 

针对上一篇文章:https://blog.csdn.net/SunShinessx/article/details/90293626,本篇用Object.defineProperty实现修改可监听的数据驱动:

/* 修改可监听的数据绑定 */
function Sue(options) {
    initData(this,options)
    if (typeof options.ready === 'function') {
        options.ready.call(this)
    }
}

function initData (vm,options) {
    var data = options.data;
    data = typeof data === 'function' ? data() : data || {};
    for (let key in data) {
        if (data.hasOwnProperty(key)) {
            let value = data[key]
           Object.defineProperty(vm,key,{
               enumerable: true,
               configurable: true,
               get() {
                   console.log(`get ${key}`);
                   return value
               },
               set(newVal) {
                   if(value !== newVal){
                       value = newVal
                       console.log(`set ${key}`);
                   }
               }
           })
        }
    }
}

var sue =  new Sue({
    data(){
        return {
            name:'ssx',
            age:18
        }
    },
    ready(){
        console.log("name",this.name);
        console.log("age",this.age);
        this.name = 'lili'
        this.age = 19
    }
})
console.log(sue.name);
console.log(sue.age);


存在的问题:如果data是一个对象,对对象的修改将不能监听到。

解决方法:遍历data对象,然后对data对象的属性也做 Object.defineProperty处理。

/* 修改可监听的数据绑定---data的属性是对象 */
function Sue(options) {
    initData(this,options)
    if (typeof options.ready === 'function') {
        options.ready.call(this)
    }
}

function initData (vm,options) {
    var data = options.data;
    data = typeof data === 'function' ? data() : data || {};
    _each(vm,data)
}

function _each(obj,sourceObj) {
    bindData(obj,sourceObj)
    for (let key in sourceObj) {
        if(typeof sourceObj[key] == 'object'){
            bindData(sourceObj[key],sourceObj[key])
        }

    }
}

function bindData(obj,sourceObj) {
    for (let key in sourceObj) {
        if (sourceObj.hasOwnProperty(key)) {
            let value = sourceObj[key]
            Object.defineProperty(obj,key,{
                enumerable: true,
                configurable: true,
                get() {
                    console.log(`get ${key}`);
                    return value
                },
                set(newVal) {
                    if(value !== newVal){
                        value = newVal
                        console.log(`set ${key}`);
                    }
                }
            })
        }
    }
}

var sue =  new Sue({
    data(){
        return {
            info:{
                name:'ssx',
                age:18
            }
        }
    },
    ready(){
        console.log("name",this.info.name);
        console.log("age",this.info.age);
        this.info.name = 'lili'
        this.info.age = 19
    }
})



存在问题:如果info的属性在开发过程中新增加了,是不能检测到的。

解决方法:vue.$set方法就是解决这个问的。简化后的$set方法可以这样实现:

/* 修改可监听的数据绑定---data对象属性随意增加也可以监听到 */
function Sue(options) {
    this.initData(this,options)
    if (typeof options.ready === 'function') {
        options.ready.call(this)
    }
}

Sue.prototype = {
    constructor:Sue,
    $set(obj,key,value){
        Object.defineProperty(obj,key,{
            enumerable: true,
            configurable: true,
            get() {
                console.log(`get ${key}`);
                return value
            },
            set(newVal) {
                if(value !== newVal){
                    value = newVal
                    console.log(`set ${key}`);
                }
            }
        })
    },
    initData (vm,options) {
    var data = options.data;
    data = typeof data === 'function' ? data() : data || {};
    this._each(vm,data)
},
    _each(obj,sourceObj) {
        this.bindData(obj,sourceObj)
        for (let key in sourceObj) {
            if(typeof sourceObj[key] == 'object'){
                this.bindData(sourceObj[key],sourceObj[key])
            }

        }
    },
    bindData(obj,sourceObj) {
        for (let key in sourceObj) {
            if (sourceObj.hasOwnProperty(key)) {
                let value = sourceObj[key]
                Object.defineProperty(obj,key,{
                    enumerable: true,
                    configurable: true,
                    get() {
                        console.log(`get ${key}`);
                        return value
                    },
                    set(newVal) {
                        if(value !== newVal){
                            value = newVal
                            console.log(`set ${key}`);
                        }
                    }
                })
            }
        }
    }
}


var sue =  new Sue({
    data(){
        return {
            info:{
                name:'ssx',
                age:18
            }
        }
    },
    ready(){
        console.log("name",this.info.name);
        console.log("age",this.info.age);
        this.info.name = 'lili'
        this.info.age = 19
    }
})
sue.$set(sue.info,'school','福大')
console.log("school",sue.info.school)


 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值