23

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

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

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

更多的信息:

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

7 回答 7

6

据我所知,没有在 Object 属性更改时触发任何事件(编辑:显然除了 for 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)
});

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

  1. 基于 Gecko/Webkit 的浏览器:观察input.form
  2. 同样在基于 Webkit 的浏览器中:在 s 上观察keyuppaste事件(由于某种原因,textarea它们不会input在s 上触发)。textarea
  3. IE:观察keyuppasteform
  4. 观察(这在 schangeform触发select)。
  5. 对于keyup和事件,通过将文本字段与其paste默认值进行比较,将字段的当前值与其默认值(页面加载时的值)进行比较valuedefaultValue

编辑:这是我为防止未修改的表单提交等而开发的示例代码:

通过javascript跟踪表单更改的最佳方法是什么?

于 2008-10-27T17:18:42.037 回答
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');

考虑到您的意见,我将在表单对象上使用事件委托来更新注册表并触发注册的观察方法。

到目前为止,这对我来说效果很好......你们能看到这有什么问题吗?

于 2008-10-28T10:56:08.720 回答
2

您可以将侦听器附加到容器(主体或表单),然后使用事件参数对更改做出反应。你得到了所有监听器的好处,但只需要为容器附加一个,而不是为每个元素附加一个。

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

event.target 保存被点击的元素。

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

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

于 2008-10-27T17:10:35.860 回答
1

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

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

于 2008-10-27T17:16:44.820 回答
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/

于 2015-09-01T16:10:00.153 回答
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 完全兼容($ 没有问题)

链接:首页我目前使用的版本

于 2008-10-27T17:25:51.540 回答
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 事件 API 的简化版,运行良好!这是一个更完整的例子

于 2013-02-28T20:19:52.877 回答