Можно ли прослушивать изменения атрибутов объекта в JavaScript? - PullRequest
23 голосов
/ 27 октября 2008

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

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

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

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

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

Ответы [ 7 ]

6 голосов
/ 28 октября 2008

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

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');

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

Пока это хорошо работает для меня ... вы, ребята, видите какие-нибудь проблемы с этим?

6 голосов
/ 27 октября 2008

Насколько я знаю, при изменении атрибутов объекта не происходит никаких событий (правка: кроме, по-видимому, 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)
});

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

  1. Браузеры на базе Gecko / Webkit: Наблюдайте input на form.
  2. Также в браузерах на основе Webkit: наблюдает keyup и paste события на textarea с (по некоторым причинам они не запускаются input на textarea с).
  3. IE: соблюдать keyup и paste на form
  4. Наблюдайте change на form (срабатывает select с).
  5. Для событий keyup и paste сравните текущее значение поля с его значением по умолчанию (каким оно было при загрузке страницы), сравнив value текстового поля с defaultValue

Редактировать: Вот пример кода, который я разработал для предотвращения отправки неизмененной формы и тому подобное:

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

2 голосов
/ 27 октября 2008

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

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

Event.target содержит элемент, по которому щелкнули.

SitePoint содержит хорошее объяснение делегирования события:

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

1 голос
/ 01 сентября 2015

Небольшая модификация предыдущего ответа: перемещая наблюдаемый код в объект, можно сделать из него абстракцию и использовать ее для расширения других объектов с помощью метода extends 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/

1 голос
/ 27 октября 2008

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

Вы профилировали страницу с помощью Firebug, чтобы получить точное представление о том, что вызывает медлительность, или это "множество обработчиков событий" - предположение?

0 голосов
/ 01 марта 2013

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

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...})

Это упрощение API DOM Events и работает просто отлично! Вот более полный пример

0 голосов
/ 27 октября 2008

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...