Мне было интересно, есть ли какой-нибудь ненавязчивый способ подключиться к таким методам, как attr, data, css и т. д., И вызвать настраиваемые триггеры?
В идеале я мог бы сделать что-то вроде этого:
$(".friend a").bind("attr.changed", changed /* data */, function(e) {
alert("The " + changed.attribute + " attribute changed from " + changed.from + " to " + changed.to + "!");
});
$(".friend").append(
$("<a/>").
attr("href", "#").
html("Friend 1").
click(function() { alert('I was clicked!'); }); // creates the element, doesn't execute since element didn't exist
$(".friends a").each(function() {
var $this = $(this);
$this.attr("rel", "friend"); // triggers "attr.changed"
});
В идеале это можно было бы запускать для любого элемента и передавать измененный attr, from и to в объекте, в вызов триггера изнутри каждого метода jQuery.



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Для этого в jQuery нет события.
плагин livequery может предоставить что-то из того, что вам нужно, например, изменение классов. В основном селектор сохраняется, а затем любые изменения в DOM, которые меняют то, что влияет на селектор, затем вызывают переданные функции и т. д.
И почему бы вам не воспользоваться самым простым подходом:
jQuery.fn.changeAttr = function(attrName,attrValue) {
return this.each(function(){
this.attr(attrName,attrValue);
alert('The att: '+attrName+ ' is now '+attrValue);
});
};
А потом просто:
$('.friends a').changeAttr('rel','friend')
Извините, если это не сработает, я точно не помню синтаксис расширения jQuery.
Вот модификация attr() в соответствии с тем, о чем вы говорите.
(function(attr) {
jQuery.attr = function(elem, name, value) {
var current = attr(elem, name, undefined); // read current value
var retval = current;
if (value !== undefined) { // writing
retval = attr(elem, name, value); // call original
jQuery.event.trigger('attr.changed', {
attribute: name,
from: current,
to: value
}, elem)
}
return retval; // return original
}
})(jQuery.attr);
Использование должно быть:
$(".friend a").bind("attr.changed", function(e, changed) {
alert("The " + changed.attribute + " attribute changed from " + changed.from + " to " + changed.to + "!");
});
$(".friends a").attr("class", "foo"); // triggers alert
Я не верю, что css() возможен, поскольку свойство .style не может запускать события. data() Не знаю.
Обратите внимание, я не оправдываю его использования, это было всего лишь академическим усилием. То, что вы хотите, приводит к снижению производительности на attr(), чтобы заполнить свойство from аргумента события. Мы должны прочитать старое значение, прежде чем записывать новое.
Написать функцию "перехвата" довольно просто:
function hook(original, wrapper) {
return function() {
wrapper.apply(this, arguments);
return original.apply(this, arguments);
}
}
Предоставленная вами функция wrapper будет вызываться с теми же аргументами, что и функция original, до вызова самой исходной функции.
Пример использования:
$.fn.attr = hook($.fn.attr, function(attribute, value) {
alert('attribute: '+attribute+', value: '+value);
});
$('a.pie').attr('href', 'http://blueberry.pie');
// An alert says "attribute: href, value: http://blueberry.pie"
(Примечание: было бы простым расширением позволить вашему wrapper также отменить вызов функции original, но это становится более функциональным, чем вы хотели.)
Вы можете использовать это напрямую, чтобы делать то, что хотите, или вы можете заставить функцию wrapper просто запускать пользовательские события jquery, которые вы прослушиваете стандартными способами jquery.
Оказывается, этот прием сработает; Я использую встроенные в данные триггеры setData (и вышеупомянутую «ловушку» для добавления функциональности поверх attr и removeAttr jQuery) для дублирования атрибутов в объекте данных в объекте jQuery. Хотя это несколько грязно, у меня есть возможность подключаться к триггерам изменения данных для data, attr и, если они написаны, любых других методов jQuery, которые отслеживают пары ключ / значение.
(function($) {
var binder = function(e, dataKey, dataValue) {
return (function(dataKey, dataValue, self) {
var $this = $(self),
oldValue = $this.data(dataKey),
newValue = dataValue,
passed = {
attr: dataKey,
from: oldValue,
to: newValue
};
var isAttribute = !!($this.data(dataKey + "-attribute"));
if (oldValue !== newValue) {
var attrPrefix = isAttribute ? "attr-" : "";
$this.trigger(attrPrefix + dataKey + "-changed", passed);
$this.trigger(attrPrefix + "data-changed", passed);
}
})(dataKey, dataValue, this);
};
var hook = function(original, wrapper) {
return function() {
wrapper.apply(this, arguments);
return original.apply(this, arguments);
};
};
$.fn.attr = hook($.fn.attr, function(attr, val) {
if (val) {
$(this).data(attr + "-attribute", true);
$(this).data(attr, val);
}
});
$.fn.removeAttr = hook($.fn.removeAttr, function(attr) {
$(this).removeData(attr + "-attribute");
$(this).removeData(attr);
});
$.fn.observeData = function() {
$(this).bind("setData", binder);
};
})(jQuery);
Этот плагин существует, но с немного другим api: github.com/aheckmann/jquery.hook/blob/master/jquery.hook.js