Возможно ли прослушивание изменений атрибутов объекта в JavaScript?
Я работаю над файловым веб-интерфейсом, который в основном построен с использованием JavaScript. Его в основном одна (очень) большая форма со многими разделами. Каждый раздел построен на основе опций из других частей формы. Всякий раз, когда эти параметры меняются, новые значения отмечаются в объекте типа "реестр", а остальные разделы повторно заполняются соответствующим образом.
Наличие прослушивателей событий во многих полях формы начинает замедлять работу, а обновление всей формы для каждого изменения будет слишком тяжелым/медленным для пользователя.
Мне интересно, можно ли добавить слушателей к атрибутам объекта реестра, а не к элементам формы, чтобы немного ускорить работу? И если да, можете ли вы указать/указать мне пример кода?
Дополнительная информация:
- Это плагин для jQuery, поэтому любая функциональность, которую я могу встроить из этой библиотеки, будет полезна, но не существенна.
- Наши пользователи используют IE6/7, Safari и FF2/3, поэтому, если это возможно, но только для "современных" браузеров мне придется найти другое решение.
Ответы
Ответ 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 и работает отлично!
Вот более полный пример