JQuery: Как прослушивать изменения DOM?
Возможно ли это и как я могу слушать изменения во всем дереве DOM с помощью jQuery?
Моя конкретная проблема: у меня есть функция "tooltip", которая стильно отображает атрибут title
, когда вы делаете hover
для любого элемента html. Однако, когда вы делаете зависание, по стандарту браузер отображает title
в своем собственном окне. Я хотел бы это подавить. Так что я думал о том, чтобы перенести содержимое атрибута title
в пользовательский (HTML5) data-title
атрибут при первой загрузке страницы, а затем моя функция подсказки будет работать с data-title
.
Проблема в том, что позже я мог бы добавлять/удалять/изменять HTML динамически, поэтому мне нужно "переподтвердить" эти элементы - снова измените эти атрибуты title. Было бы неплохо, если бы слушатель событий прослушал такие изменения для меня и автоматически перезаписывал элементы.
Ответы
Ответ 1
Мое лучшее предположение заключается в том, что вы хотите слушать события мутации DOM.
Вы можете сделать это с помощью события мутации DOM как любое нормальное событие javascript, например щелчок мышью.
Обратитесь к этому: W3 MutationEvent
Пример:
$("element-root").bind("DOMSubtreeModified", "CustomHandler");
Ответ 2
[отредактировано в ответ на исследование члена Тони]
Итак, без дополнительного кода это немного слепой, но мне кажется, что здесь есть две вещи: 1. поведение всплывающей подсказки браузера по умолчанию; 2. потенциально обновленный DOM и возможность для ваших пользовательских всплывающих подсказок продолжать работу.
Относительно # 1: , когда вы привязываете свое настраиваемое событие к элементу, вы можете использовать event.preventDefault()
, чтобы всплывающие подсказки не отображались. Это не работает должным образом. Таким образом, обходным путем для продолжения использования атрибута "title" является захват значения, вставка его в объект данных (функция $.data()
), а затем нулевое название с пустой строкой (removeAttr несовместимо). Затем на mouseleave вы извлекаете значение из объекта данных и вставляете его обратно в заголовок. Эта идея приходит отсюда: Как отключить всплывающую подсказку в браузере с помощью jQuery?
Относительно # 2: вместо повторной привязки к изменению DOM вам просто нужно привязать один раз к элементу прослушивателя, который никогда не должен быть уничтожен. Обычно это элемент контейнера какого-то типа, но он может даже быть document
(приближается .live()
, который теперь устарел), если вам действительно нужен контейнер, содержащий все объекты. Здесь образец, который использует некоторую поддельную разметку моего собственного проекта:
var container = $('.section');
container.on('mouseenter', 'a', function() {
var $this = $(this);
var theTitle = $this.attr('title');
$this.attr('title', '');
$('#notatooltip').html(theTitle);
$.data(this, 'title', theTitle);
});
container.on('mouseleave', 'a', function() {
$('#notatooltip').html('');
var $this = $(this);
var storedTitle = $.data(this, 'title');
$this.attr('title', storedTitle);
});
Моя нереалистичная разметка (только для этого примера) находится здесь:
<div class="section">
<a href="#" title="foo">Hover this foo!</a>
<div id="notatooltip"></div>
</div>
И скрипка здесь: http://jsfiddle.net/GVDqn/
Или с некоторыми проверками здравомыслия: http://jsfiddle.net/GVDqn/1/
Вероятно, более оптимальный способ сделать это (я честно не исследовал, если бы вы могли привязать две отдельные функции к двум отдельным событиям с одним селектором), но это сделает трюк.
Вам не нужно повторно связываться на основе изменения DOM, делегированный прослушиватель автоматически обрабатывает его. И вы должны быть в состоянии предотвратить функциональность всплывающей подсказки по умолчанию, просто предотвратив ее.
Ответ 3
Вам нужно посмотреть здесь: http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-eventgroupings-mutationevents
Ответ 4
Как отмечено Грегом Петтитом, вы должны использовать функцию on() для элемента.
Это позволяет привязать селектор к событию, затем jQuery добавит этот обработчик событий, когда доступны объекты, возвращаемые селектором.
Если вы хотите, чтобы функция срабатывала над мышью над событием, и вы хотели, чтобы она запускала все элементы с классом * field_title *, вы бы сделали следующее:
$('.field_title').bind('mouseenter', function() { doSomething(); });
Это вызовет событие over mouse over для любых объектов класса * field_title * и выполнит функцию doSomething().
Надеюсь, что это имеет смысл:)