位置:海鸟网 > IT > JavaScript >

javascript中依赖属性(Dependency Property)的实现

好久没在首页发点东西了,昨天在上依照wpf中依赖属性的思想尝试写了基本的功能.这里拿出来与大家分享

Demo1 注册依赖属性

step1 定义一个函数

function Person() {
    this.render = function () { }
};

step2 注册依赖属性

第三个参数是属性变更回调

dp.reg(Person, "name", "terry", function (obj) {
    obj.render();
    alert(obj.oldValue);
    alert(obj.newValue);
});
setp3 修改依赖属性值

上面的回调方法触发了,至于具体这个功能用在什么场合,你懂的

dp.setValue(entity, "name", "zhang");
Demo2 注册只读依赖属性

下面的回调方法将会触发

dp.regReadOnly(Person, "sex", "boy", function (obj) {
    alert(obj.newValue);
});
另外还可以添加一个属性验证回调,如下,因为年龄不可能小于0

dp.reg(Person, "age", 25, function (obj) {
}, function (value) {
    if (value < 1)
        return 1;
    return value;
});
Demo3 读写依赖属性

用setValue和getValue方法

var entity = new Person();

dp.getValue(entity, "age")
dp.setValue(entity, "name", "xinghao");
Demo4 默认属性值

在注册依赖属性时就有一个默认的值,可通过下面方法查看和恢复默认值

dp.getDefaultValue(entity, "name");
dp.clearValue(entity, "name");
Demo5 注销依赖属性

dp.unreg("Person", "name");

说明:以上通过依赖属性注册的属性不会存在原有对象中,即注册了Person,但不会影响Person本身对象.那么久是说依赖属性是一个可插拔的功能.如果你还没有过这种属性定义的尝试的话,那么来试一下吧。我将继续完善其功能,并与大家分享(假设你还没有依赖属性的概念,也可以尝尝鲜)

最后奉上完整代码,尚未完善,大家提意见吧


(function (container) {

    var ORIGINAL_TYPE = "originalType",
    PREFIX = "dp"

    //utility
    function getPropName(obj) {
        return PREFIX + obj.originalType;
    }

    function getFnName(obj) {
        var fundoc = obj.prototype ? obj.toString() : obj.constructor.toString(),
        funcName = fundoc.split('(')[0].split(' ')[1];
        return funcName;
    }

    var dpos = [];
    container.dp = {};

    function propertyMetadata(propertyName, defaultValue, propertyChangedCallback) {
        this.PropertyName = propertyName;
        this.DefaultValue = defaultValue;
        this.PropertyChangedCallback = propertyChangedCallback;
    };

    propertyMetadata.prototype = {
        PropertyName: "",
        isReadOnly: false,
        Value: undefined,
        DefaultValue: undefined,
        CoerceValueCallback: undefined,
        PropertyChangedCallback: function () { }
    };

    function dpObject(entity) {
        this.objectType = entity;
        this.dmps = {};

    };

    dpObject.prototype = {
        addDmp: function (propertyName, defaultValue, propChanged, coerceValueCallback) {
            if (this.dmps[propertyName]) return;

            var dmp = new propertyMetadata(propertyName, defaultValue, propChanged);
            dmp.CoerceValueCallback = coerceValueCallback;
            this.dmps[propertyName] = dmp;
            return dmp;
        },
        getDmpCount: function () {
            return this.dmps.lenth;
        },
        getPropValue: function (propertyName,prop) {
            var dmp = this.dmps[propertyName];
            return dmp[prop];
        },
        getDmp: function (propertyName) {
            return this.dmps[propertyName];
        },
        clearDmp: function (propertyName) {
            this.dmps[propertyName] = undefined;
            delete this.dmps[propertyName];
        },
        setValue: function (obj, prop, newValue) {
            var dmp = this.dmps[prop];
            if (!dmp || dmp.isReadOnly) return;

            var oldValue = dmp.Value || dmp.DefaultValue;

            if (dmp.CoerceValueCallback)
                newValue = dmp.CoerceValueCallback(newValue);

            if (newValue !== oldValue)
                dmp.Value = newValue;
            if (dmp.PropertyChangedCallback) {
                var changedArgs = { obj: obj, prop: prop, oldValue: oldValue, newValue: newValue }
                dmp.PropertyChangedCallback(changedArgs);
            }
        },
        getValue: function (prop) {
            var dmp = this.dmps[prop];
            return dmp.Value ? dmp.Value : dmp.DefaultValue;
        },
        getDefaultValue: function (prop) {
            var dmp = this.dmps[prop];
            return dmp.DefaultValue;
        },
        clearValue: function (prop) {
            var dmp = this.dmps[prop];
            dmp.Value = undefined;
        }
    };

    dp.unReg = function (obj, prop) {
        var className = getFnName(obj),
        dpo = dpos[className];
        dpo.clearDmp(prop);
    };

    dp.isReged = function (obj, prop) {
        var className = getFnName(obj),
        dpo = dpos[className];
        if (!prop)
            return dpo.getDmpCount() > 0;

        return dpo.getDmp(prop) == undefined;
    };

    dp.isReadOnly=function(obj,prop) {
        var dpo = getDpo(obj);
        return dpo.getPropValue(prop, "isReadOnly");
    };

    dp.reg = function (obj, prop, value, propChanged, coerceValueCallback, isReadOnly) {
        var className = getFnName(obj),
        dpo = dpos[className] = dpos[className] || new dpObject(className);
        dpo.addDmp(prop, value, propChanged, coerceValueCallback);
        if (isReadOnly) {
            var dmp = dpo.getDmp(prop);
            dmp.isReadOnly = true;
        }
    };
    dp.regReadOnly = function (obj, prop, value, propChanged, coerceValueCallback) {
        dp.reg(obj, prop, value, null, null, true);
    };

    function getDpo(obj) {
        var className = getFnName(obj),
        dpo = dpos[className];
        return dpo;
    };

    dp.setValue = function (obj, prop, value) {
        var dpo = getDpo(obj);
        dpo.setValue(obj, prop, value);
    };

    dp.getValue = function (obj, prop) {
        var dpo = getDpo(obj);
        return dpo.getValue(prop, value);
    };

    dp.getDefaultValue = function (obj, prop) {
        var dpo = getDpo(obj);
        return dpo.getDefaultValue(prop);
    };

    dp.clearValue = function (obj, prop) {
        var dpo = getDpo(obj);
        dpo.clearValue(prop);
    };

})(window);

function Person() {
    this.render = function () { }
};

dp.reg(Person, "name", "terry", function (obj) {
    obj.render();
    alert(obj.oldValue);
    alert(obj.newValue);
});

dp.setValue(entity, "name", "zhang");

dp.reg(Person, "age", 25, function (obj) {
}, function (value) {
    if (value < 1)
        return 1;
    return value;
});

dp.regReadOnly(Person, "sex", "boy", function (obj) {
    alert(obj.newValue);
});

dp.setValue(entity, "age", -1);

var entity = new Person();

dp.getValue(entity, "age")
dp.setValue(entity, "name", "xinghao");
alert(dp.isReged(entity);
alert(dp.getValue(entity, "name"));
dp.getDefaultValue(entity, "name");
dp.clearValue(entity, "name");
alert(dp.getValue(entity, "name"));
dp.unreg("Person", "name");
dp.setValue(entity, "name", "zhang");