是否可以在JavaScript中侦听对象属性的更改?

时间:2008-10-27 16:49:48

标签: javascript javascript-events

我正在开发一个主要使用JavaScript构建的网络界面。它基本上是一个(非常)大的形式,有许多部分。每个部分都是基于表单其他部分的选项构建的。每当这些选项更改时,新值将在“注册表”类型对象中记录,其他部分将相应地重新填充。

在许多表单字段上拥有事件侦听器会开始减慢速度,并且为每个更改刷新整个表单对用户来说太重/太慢。

我想知道是否有可能将侦听器添加到注册表对象的属性而不是表单元素来加快速度?如果是这样,你能提供/指出一些示例代码吗?

更多信息:

  • 这是jQuery的一个插件,所以我可以从该库中构建的任何功能都会有所帮助,但不是必需的。
  • 我们的用户正在使用IE6 / 7,Safari和FF2 / 3,所以如果可以,但仅限于“现代”浏览器,我将不得不找到不同的解决方案。

7 个答案:

答案 0 :(得分:6)

据我所知,没有事件触发对象属性更改(编辑:显然,除了Object.watch)。

为什么不尽可能使用事件委托?也就是说,表单上的事件而不是单个表单元素上的事件,在事件冒出时捕获事件?

例如(我的jQuery生锈了,请原谅我使用Prototype,但我相信你能够轻松地适应它):

$(form).observe('change', function(e) {
    // To identify changed field, in Proto use e.element()
    // but I think in jQuery it's e.target (as it should be)
});

如果您希望在文本字段失去焦点之前触发它们,您还可以捕获inputkeyuppaste个事件。我的解决方案通常是:

  1. 基于Gecko / Webkit的浏览器:input上观察form
  2. 同样在基于Webkit的浏览器中:观察keyup上的pastetextarea个事件(它们不会input textarea 1}} s由于某种原因)。
  3. IE:观察keyup
  4. 上的pasteform
  5. change上观察form(这会在select上触发)。
  6. 对于keyuppaste事件,通过将文本字段的value与其{{}进行比较,将字段的当前值与其默认值(加载页面时的值)进行比较1}}
  7. 编辑:这是我为防止未经修改的表单提交而开发的示例代码:

    What is the best way to track changes in a form via javascript?

答案 1 :(得分:6)

感谢评论家伙。我已经离开了以下内容:

var EntriesRegistry = (function(){

    var instance = null;

    function __constructor() {

        var
            self = this,
            observations = {};

        this.set = function(n,v)
        {
            self[n] = v;

            if( observations[n] )
                for( var i=0; i < observations[n].length; i++ )
                    observations[n][i].apply(null, [v, n]);

        }

        this.get = function(n)
        {
            return self[n];
        }

        this.observe = function(n,f)
        {

            if(observations[n] == undefined)
                observations[n] = [];

            observations[n].push(f);
        }

    }

    return new function(){
        this.getInstance = function(){
            if (instance == null)
            {
                instance = new __constructor();
                instance.constructor = null;
            }
            return instance;
        }
    }
})();

var entries = EntriesRegistry.getInstance();

var test = function(v){ alert(v); };

entries.set('bob', 'meh');

entries.get('bob');

entries.observe('seth', test);

entries.set('seth', 'dave');

接受您的评论,我将在表单对象上使用事件委托来更新注册表并触发已注册的观察方法。

到目前为止,这对我来说效果很好......你们有没有看到这方面的任何问题?

答案 2 :(得分:2)

您可以将侦听器附加到容器(正文或表单),然后使用event参数对更改作出反应。你得到了所有听众的善意,但只需要为容器添加一个,而不是每个元素都有一个。

$('body').change(function(event){
    /* do whatever you want with event.target here */
    console.debug(event.target); /* assuming firebug */
 });

event.target包含被点击的元素。

SitePoint对事件委派有一个很好的解释:

  

JavaScript事件委托是一种简单的技术,通过它您可以将单个事件处理程序添加到父元素,以避免必须将事件处理程序添加到多个子元素。

答案 3 :(得分:1)

Mozilla引擎浏览器支持Object.watch,但我不知道跨浏览器兼容的等价物。

您是否使用Firebug对页面进行了分析,以确切了解导致缓慢的原因,或“猜测很多事件处理程序”?

答案 4 :(得分:1)

对前一个答案的小修改:通过将可观察代码移动到一个对象,可以从中抽象出来并使用它来使用jQuery的extend方法扩展其他对象。

ObservableProperties = {
    events : {},
    on : function(type, f)
    {
        if(!this.events[type]) this.events[type] = [];
        this.events[type].push({
            action: f,
            type: type,
            target: this
        });
    },
    trigger : function(type)
    {
        if (this.events[type]!==undefined)
        {
            for(var e = 0, imax = this.events[type].length ; e < imax ; ++e)
            {
                this.events[type][e].action(this.events[type][e]);
            }
        }
    },
    removeEventListener : function(type, f)
    {
        if(this.events[type])
        {
            for(var e = 0, imax = this.events[type].length ; e < imax ; ++e)
            {
                if(this.events[type][e].action == f)
                    this.events[type].splice(e, 1);
            }
        }
    }
};
Object.freeze(ObservableProperties);

var SomeBusinessObject = function (){
    self = $.extend(true,{},ObservableProperties);
    self.someAttr = 1000
    self.someMethod = function(){
        // some code
    }
    return self;
}

请参阅小提琴:https://jsfiddle.net/v2mcwpw7/3/

答案 5 :(得分:0)

jQuery真是太神奇了。虽然你可以看一下ASP.NET AJAX Preview。

某些功能只是.js文件,不依赖于.NET。也许你可以找到有用的观察者模式实现。

var o = { foo: "Change this string" };

Sys.Observer.observe(o);

o.add_propertyChanged(function(sender, args) {
    var name = args.get_propertyName();
    alert("Property '" + name + "' was changed to '" + sender[name] + "'.");
});

o.setValue("foo", "New string value.");

此外,客户端模板已准备好用于一些有趣的场景。

最后一点,这与jQuery完全兼容(没有问题)

链接:Home pageVersion I currently use

答案 6 :(得分:0)

我正在寻找同样的事情并提出你的问题......没有一个答案满足我的需求所以我提出了这个我想分享的解决方案:

var ObservedObject = function(){
    this.customAttribute = 0
    this.events = {}
    // your code...
}
ObservedObject.prototype.changeAttribute = function(v){
     this.customAttribute = v
     // your code...
     this.dispatchEvent('myEvent')
}
ObservedObject.prototype.addEventListener = function(type, f){
    if(!this.events[type]) this.events[type] = []
    this.events[type].push({
        action: f,
        type: type,
        target: this
    })
}
ObservedObject.prototype.dispatchEvent = function(type){
    for(var e = 0; e < this.events[type].length; ++e){
        this.events[type][e].action(this.events[type][e])
    }
}
ObservedObject.prototype.removeEventListener = function(type, f){
    if(this.events[type]) {
        for(var e = 0; e < this.events[type].length; ++e){
            if(this.events[type][e].action == f)
                this.events[type].splice(e, 1)
        }
    }
}

var myObj = new ObservedObject()

myObj.addEventListener('myEvent', function(e){// your code...})

这是DOM Events API的简化,效果很好! 这是一个更完整的example