2008-10-27 7 views
23

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

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

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

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

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

ответ

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

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

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

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

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

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

1

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

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

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

Вы также можете захватить 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

Edit: Вот пример код, я разработал для предотвращения неизмененной формы представления и т.п.:

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

+0

Object.observe() является устаревшим. Старайтесь не использовать это как можно больше для себя. – andersfylling 2016-05-04 21:13:14

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 page, Version I currently use

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

Это упрощение API DOM Events и работает отлично! Подробнее example

1

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

+0

Можно утверждать, что мы можем привязать объект ObservableProperties непосредственно к бизнес-объекту, выполнив `$ .extend (true, this, ObservableProperties);` Это выглядит лучше. Однако будьте осторожны с областью применения. Я использую `self`variable, когда я делаю что-то немного сложное с областью действия (или, например, с Singleton), иначе, если все открыто, я иду с этим. См. [Эта скрипка] (https://jsfiddle.net/empx6z58/) – 2016-01-14 12:32:32

Смежные вопросы