Jak wspomniano w kilku innych odpowiedziach, zdarzenia mutacji zostały wycofane, więc powinieneś używać MutationObserver zamiast tego . Ponieważ nikt jeszcze nie podał żadnych szczegółów na ten temat, proszę bardzo ...
Podstawowy interfejs API JavaScript
Interfejs API dla MutationObserver jest dość prosty. Nie jest to tak proste, jak zdarzenia mutacji, ale nadal jest w porządku.
function callback(records) {
records.forEach(function (record) {
var list = record.addedNodes;
var i = list.length - 1;
for ( ; i > -1; i-- ) {
if (list[i].nodeName === 'SELECT') {
console.log(list[i]);
}
}
});
}
var observer = new MutationObserver(callback);
var targetNode = document.body;
observer.observe(targetNode, { childList: true, subtree: true });
<script>
setTimeout(function() {
var $el = document.createElement('select');
document.body.appendChild($el);
}, 500);
</script>
Rozbijmy to.
var observer = new MutationObserver(callback);
To tworzy obserwatora. Obserwator jeszcze niczego nie ogląda; to jest właśnie miejsce, w którym zostaje dołączony detektor zdarzeń.
observer.observe(targetNode, { childList: true, subtree: true });
To sprawia, że obserwator zaczyna działać. Pierwszym argumentem jest węzeł, na którym obserwator będzie obserwował zmiany. Drugi argument to opcje, na co należy uważać .
childList
oznacza, że chcę obserwować dodawanie lub usuwanie elementów podrzędnych.
subtree
to modyfikator, który rozciąga się, childList
aby obserwować zmiany w dowolnym miejscu poddrzewa tego elementu (w przeciwnym razie sprawdzałby tylko zmiany bezpośrednio w obrębie tego elementu targetNode
).
Pozostałe dwie główne opcje childList
to attributes
i characterData
, co oznacza, jak brzmią. Musisz użyć jednego z tych trzech.
function callback(records) {
records.forEach(function (record) {
Sprawy stają się trochę skomplikowane w wywołaniu zwrotnym. Wywołanie zwrotne otrzymuje tablicę MutationRecord s. Każdy MutationRecord można opisać kilka zmian jednego typu ( childList
, attributes
lub characterData
). Ponieważ powiedziałem obserwatorowi tylko, żeby na niego uważał childList
, nie będę się trudził sprawdzaniem typu.
var list = record.addedNodes;
Tutaj pobieram listę NodeList wszystkich dodanych węzłów podrzędnych. Będzie to puste dla wszystkich rekordów, do których nie dodano węzłów (a takich rekordów może być wiele).
Od tego momentu przeglądam dodane węzły i znajduję te, które są <select>
elementy.
Nie ma tu nic naprawdę skomplikowanego.
jQuery
... ale prosiłeś o jQuery. W porządku.
(function($) {
var observers = [];
$.event.special.domNodeInserted = {
setup: function setup(data, namespaces) {
var observer = new MutationObserver(checkObservers);
observers.push([this, observer, []]);
},
teardown: function teardown(namespaces) {
var obs = getObserverData(this);
obs[1].disconnect();
observers = $.grep(observers, function(item) {
return item !== obs;
});
},
remove: function remove(handleObj) {
var obs = getObserverData(this);
obs[2] = obs[2].filter(function(event) {
return event[0] !== handleObj.selector && event[1] !== handleObj.handler;
});
},
add: function add(handleObj) {
var obs = getObserverData(this);
var opts = $.extend({}, {
childList: true,
subtree: true
}, handleObj.data);
obs[1].observe(this, opts);
obs[2].push([handleObj.selector, handleObj.handler]);
}
};
function getObserverData(element) {
var $el = $(element);
return $.grep(observers, function(item) {
return $el.is(item[0]);
})[0];
}
function checkObservers(records, observer) {
var obs = $.grep(observers, function(item) {
return item[1] === observer;
})[0];
var triggers = obs[2];
var changes = [];
records.forEach(function(record) {
if (record.type === 'attributes') {
if (changes.indexOf(record.target) === -1) {
changes.push(record.target);
}
return;
}
$(record.addedNodes).toArray().forEach(function(el) {
if (changes.indexOf(el) === -1) {
changes.push(el);
}
})
});
triggers.forEach(function checkTrigger(item) {
changes.forEach(function(el) {
var $el = $(el);
if ($el.is(item[0])) {
$el.trigger('domNodeInserted');
}
});
});
}
})(jQuery);
Spowoduje to utworzenie nowego zdarzenia o nazwie domNodeInserted
przy użyciu interfejsu API wydarzeń specjalnych jQuery . Możesz go używać w ten sposób:
$(document).on("domNodeInserted", "select", function () {
$(this).combobox();
});
Osobiście sugerowałbym szukanie klasy, ponieważ niektóre biblioteki będą tworzyć select
elementy do celów testowych.
Oczywiście możesz również użyć .off("domNodeInserted", ...)
lub dostosować obserwację, przekazując dane w następujący sposób:
$(document.body).on("domNodeInserted", "select.test", {
attributes: true,
subtree: false
}, function () {
$(this).combobox();
});
Spowodowałoby to sprawdzanie wyglądu select.test
elementu, gdy atrybuty elementów uległy zmianie bezpośrednio w treści.
Możesz to zobaczyć na żywo poniżej lub na jsFiddle .
(function($) {
$(document).on("domNodeInserted", "select", function() {
console.log(this);
});
})(jQuery);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script>
setTimeout(function() {
var $el = document.createElement('select');
document.body.appendChild($el);
}, 500);
</script>
<script>
(function($) {
var observers = [];
$.event.special.domNodeInserted = {
setup: function setup(data, namespaces) {
var observer = new MutationObserver(checkObservers);
observers.push([this, observer, []]);
},
teardown: function teardown(namespaces) {
var obs = getObserverData(this);
obs[1].disconnect();
observers = $.grep(observers, function(item) {
return item !== obs;
});
},
remove: function remove(handleObj) {
var obs = getObserverData(this);
obs[2] = obs[2].filter(function(event) {
return event[0] !== handleObj.selector && event[1] !== handleObj.handler;
});
},
add: function add(handleObj) {
var obs = getObserverData(this);
var opts = $.extend({}, {
childList: true,
subtree: true
}, handleObj.data);
obs[1].observe(this, opts);
obs[2].push([handleObj.selector, handleObj.handler]);
}
};
function getObserverData(element) {
var $el = $(element);
return $.grep(observers, function(item) {
return $el.is(item[0]);
})[0];
}
function checkObservers(records, observer) {
var obs = $.grep(observers, function(item) {
return item[1] === observer;
})[0];
var triggers = obs[2];
var changes = [];
records.forEach(function(record) {
if (record.type === 'attributes') {
if (changes.indexOf(record.target) === -1) {
changes.push(record.target);
}
return;
}
$(record.addedNodes).toArray().forEach(function(el) {
if (changes.indexOf(el) === -1) {
changes.push(el);
}
})
});
triggers.forEach(function checkTrigger(item) {
changes.forEach(function(el) {
var $el = $(el);
if ($el.is(item[0])) {
$el.trigger('domNodeInserted');
}
});
});
}
})(jQuery);
</script>
Uwaga
Ten kod jQuery jest dość podstawową implementacją. Nie uruchamia się w przypadkach, gdy modyfikacje w innym miejscu powodują, że twój selektor jest ważny.
Na przykład załóżmy, że twój selektor to, .test select
a dokument ma już rozszerzenie <select>
. Dodanie klasy test
do <body>
spowoduje, że selektor będzie prawidłowy, ale ponieważ sprawdzam tylko record.target
i record.addedNodes
, zdarzenie nie zostanie uruchomione. Zmiana musi nastąpić w elemencie, który chcesz sam zaznaczyć.
Można tego uniknąć, wysyłając zapytanie o selektor za każdym razem, gdy wystąpią mutacje. Zdecydowałem się tego nie robić, aby uniknąć powielania zdarzeń dla elementów, które zostały już obsłużone. Właściwe postępowanie z sąsiadującymi lub ogólnymi kombinatorami rodzeństwa mogłoby jeszcze bardziej utrudnić sprawę.
Dla bardziej kompleksowego rozwiązania, zobacz https://github.com/pie6k/jquery.initialize , jak wspomniano w Damien Ó Ceallaigh „s odpowiedź . Jednak autor tej biblioteki ogłosił, że biblioteka jest stara i sugeruje, aby nie używać do tego jQuery.
$(select).ready(function() { });