Подтвердить что ты не робот

Возможно ли прослушивание изменений атрибутов объекта в JavaScript?

Я работаю над файловым веб-интерфейсом, который в основном построен с использованием JavaScript. Его в основном одна (очень) большая форма со многими разделами. Каждый раздел построен на основе опций из других частей формы. Всякий раз, когда эти параметры меняются, новые значения отмечаются в объекте типа "реестр", а остальные разделы повторно заполняются соответствующим образом.

Наличие прослушивателей событий во многих полях формы начинает замедлять работу, а обновление всей формы для каждого изменения будет слишком тяжелым/медленным для пользователя.

Мне интересно, можно ли добавить слушателей к атрибутам объекта реестра, а не к элементам формы, чтобы немного ускорить работу? И если да, можете ли вы указать/указать мне пример кода?

Дополнительная информация:

  • Это плагин для jQuery, поэтому любая функциональность, которую я могу встроить из этой библиотеки, будет полезна, но не существенна.
  • Наши пользователи используют IE6/7, Safari и FF2/3, поэтому, если это возможно, но только для "современных" браузеров мне придется найти другое решение.
4b9b3361

Ответ 1

Спасибо за комментарии ребята. Я пошел со следующим:

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

Насколько я знаю, нет событий, связанных с изменениями атрибутов объекта (изменить: кроме, по-видимому, для Object.watch).

Почему бы не использовать делегирование событий там, где это возможно? То есть события на форме, а не на отдельных элементах формы, захватывая события, когда они пузырятся?

Например (мой jQuery ржавый, простите меня за использование Prototype, но я уверен, что вы сможете легко его адаптировать):

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

Вы также можете захватывать события input и keyup и paste, если вы хотите, чтобы они запускали текстовые поля, прежде чем они потеряли фокус. Мое решение для этого обычно:

  • Браузеры на базе Gecko/Webkit: наблюдайте input на form.
  • Также в браузерах на основе Webkit: наблюдайте keyup и paste события на textarea (они не запускают input на textarea по какой-либо причине).
  • IE: наблюдайте keyup и paste на form
  • Обратите внимание на change на form (это срабатывает при select s).
  • Для событий keyup и paste сравните текущее значение поля с его значением по умолчанию (каково его значение при загрузке страницы) путем сравнения текстового поля value с его defaultValue

Изменить: Здесь пример кода, который я разработал для предотвращения подачи немодифицированной формы и т.п.:

Каков наилучший способ отслеживания изменений в форме через javascript?

Ответ 3

Вы можете прикрепить слушателя к контейнеру (телу или форме), а затем использовать параметр события, чтобы отреагировать на изменение. Вы получаете всю доброжелательность слушателя, но только нужно прикрепить его к контейнеру вместо одного для каждого элемента.

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

В event.target содержится элемент, на который был нажат.

SitePoint имеет приятное объяснение здесь делегирования событий:

Передача событий JavaScript - это простой способ, с помощью которого вы добавляете один обработчик событий в родительский элемент, чтобы избежать необходимости добавлять обработчики событий к нескольким дочерним элементам.

Ответ 4

браузеры с Mozilla-серверами поддерживают Object.watch, но я не знаю эквивалент, совместимый с несколькими браузерами.

Профилировали ли вы страницу с Firebug, чтобы получить представление о том, что именно вызывает медленность или "много обработчиков событий"?

Ответ 5

Небольшая модификация предыдущего ответа: перемещая наблюдаемый код на объект, можно сделать абстракцию из него и использовать его для расширения других объектов с помощью метода расширения jQuery.

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/

Ответ 6

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 (не проблема с $)

Ссылки: Домашняя страница, В версии я в настоящее время используется

Ответ 7

Я искал то же самое и задал свой вопрос... ни один из ответов не удовлетворил мои потребности, поэтому я придумал это решение, которое я хотел бы поделиться:

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 и работает отлично! Вот более полный пример