纯JavaScript双向数据绑定

14

出于好奇和增加我的知识,我想在DOM元素和JavaScript变量之间实现某种双向数据绑定。

我很幸运地找到了一个优秀的解决方案来解决我的问题的一半,位于这里的stackoverflow, 这让我找到了这个gist https://gist.github.com/384583,但我仍然无法100%完成这件事。

以下是我的代码示例: http://jsfiddle.net/bpH6Z/

如果您尝试运行fiddle并单击“view Value”,则将收到undefined,而我想获取对象属性的实际值。

由于我缺乏JavaScript经验,我可能正在做错了什么,但您有任何想法为什么我无法在_bind()和_watch()调用后正确读取属性'secret'吗?

免责声明: 如我所说,我这样做是因为我想更好地了解JavaScript,并且我不打算编写我的框架。因此,任何“使用框架X”都是完全无用的,因为我可以使用angularjs完成工作。


$ 是指 jQuery 吗?那它不是纯 JS 喔。 - daslicht
可能是如何在JavaScript中实现DOM数据绑定的重复问题。 - Beginner
3个回答

5
请尝试http://jsfiddle.net/bpH6Z/4/
我已经在Object.prototype.__watch中更新了您重新定义的getter/setter,同时目前您的处理程序需要返回新值。
更新:现在您的处理程序不需要返回新设置的值。
当前代码:
//Got this great piece of code from https://gist.github.com/384583
Object.defineProperty(Object.prototype, "__watch", {
    enumerable: false,
    configurable: true,
    writable: false,
    value: function(prop, handler) {
        var val = this[prop],
            getter = function() {
                return val;
            },
            setter = function(newval) {
                val = newval;
                handler.call(this, prop, newval);
                return newval;
            };

        if (delete this[prop]) { // can't watch constants
            Object.defineProperty(this, prop, {
                get: getter,
                set: setter,
                enumerable: true,
                configurable: true
            });
        }
    }
});

var Controller = function () {
    //The property is changed whenever the dom element changes value
    //TODO add a callback ?
    this._bind = function (DOMelement, propertyName) {
        //The next line is commented because priority is given to the model
        //this[propertyName] = $(DOMelement).val();
        var _ctrl = this;
        $(DOMelement).on("change input propertyChange", function(e) {
            e.preventDefault();
            _ctrl[propertyName] = DOMelement.val();
        });

    };

    //The dom element changes values when the propertyName is setted
    this._watch = function(DOMelement, propertyName) {
        //__watch triggers when the property changes
        this.__watch(propertyName, function(property, value) {
            $(DOMelement).val(value);
        });
    };
};

var ctrl = new Controller();
ctrl.secret = 'null';
ctrl._bind($('#text1'), 'secret'); // I want the model to reflect changes in #text1
ctrl._watch($('#text2'), 'secret'); // I want the dom element #text2 to reflect changes in the model
$('#button1').click(function() {
    $('#output').html('Secret is : ' + ctrl.secret); //This gives problems
});

当前的HTML:

<html>
<head></head>
<body>
    value: <input type="text" id="text1" /><br />
    copy: <input type="text" id="text2" /><br />
    <input type="button" id="button1" value="View value"><br />
    <span id="output"></span>
</body>
</html>

这个能在IE8上工作吗?因为defineProperty只能用于DOM对象。 - Integralist
@Integralist 很可能不行,但应该试一下 - 必须重新启动到XP。 - metadings

3
您传递给 __watch 函数的处理程序缺少 return 语句。
this._watch = function(DOMelement, propertyName) {
    //__watch triggers when the property changes
    this.__watch(propertyName, function(property, value) {
        $(DOMelement).val(value);
        return value;
    })

}

因为newval被设置为来自处理程序的返回值,所以如果没有这个,它将是undefined


+1。说得太好了,比我快……我也终于注意到这个了。 - Mark Pieszak - Trilon.io

0

我已经为多个观察者增强了它。

http://jsfiddle.net/liyuankui/54vE4/

//The dom element changes values when the propertyName is setted
this._watch = function(DOMelement, propertyName) {
    //__watch triggers when the property changes
    if(watchList.indexOf(DOMelement)<0){
        watchList.push(DOMelement);
    }
    this.__watch(propertyName, function(property, value) {
        for(var i=0;i<watchList.length;i++){
            var watch=watchList[i];
            $(watch).val(value);
            $(watch).html(value);
        }
    });
};

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接