Wie in mehreren anderen Antworten erwähnt, sind Mutationsereignisse veraltet, daher sollten Sie stattdessen MutationObserver verwenden. Da noch niemand Details dazu angegeben hat, geht es los ...
Grundlegende JavaScript-API
Die API für MutationObserver ist ziemlich einfach. Es ist nicht ganz so einfach wie die Mutationsereignisse, aber es ist immer noch in Ordnung.
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>
Lassen Sie uns das aufschlüsseln.
var observer = new MutationObserver(callback);
Dies schafft den Betrachter. Der Beobachter beobachtet noch nichts; Hier wird der Ereignis-Listener angehängt.
observer.observe(targetNode, { childList: true, subtree: true });
Dadurch startet der Beobachter. Das erste Argument ist der Knoten, auf dem der Beobachter nach Änderungen sucht. Das zweite Argument sind die Optionen für das, worauf zu achten ist .
childList
bedeutet, dass ich darauf achten möchte, dass untergeordnete Elemente hinzugefügt oder entfernt werden.
subtree
ist ein Modifikator, der erweitert wird childList
, um nach Änderungen an einer beliebigen Stelle im Teilbaum dieses Elements zu suchen (andernfalls werden nur Änderungen direkt darin betrachtet targetNode
).
Die anderen beiden Hauptoptionen childList
sind attributes
und characterData
, die bedeuten, wie sie klingen. Sie müssen eine dieser drei verwenden.
function callback(records) {
records.forEach(function (record) {
Im Rückruf wird es etwas knifflig. Der Rückruf empfängt ein Array von MutationRecords . Jede MutationRecord kann mehrere Änderungen eines Typs beschreiben ( childList
, attributes
oder characterData
). Da ich dem Beobachter nur gesagt habe, er solle darauf achten childList
, werde ich den Typ nicht überprüfen.
var list = record.addedNodes;
Genau hier greife ich zu einer NodeList aller untergeordneten Knoten, die hinzugefügt wurden. Dies ist für alle Datensätze leer, bei denen keine Knoten hinzugefügt wurden (und möglicherweise gibt es viele solcher Datensätze).
Von da an durchlaufe ich die hinzugefügten Knoten und finde alle <select>
Elemente.
Nichts wirklich komplexes hier.
jQuery
... aber du hast nach jQuery gefragt. Fein.
(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);
Dadurch wird domNodeInserted
mithilfe der jQuery-API für spezielle Ereignisse ein neues Ereignis mit dem Namen erstellt . Sie können es so verwenden:
$(document).on("domNodeInserted", "select", function () {
$(this).combobox();
});
Ich würde persönlich vorschlagen, nach einer Klasse zu suchen, da einige Bibliotheken select
Elemente zu Testzwecken erstellen .
Natürlich können Sie die Wiedergabe auch verwenden .off("domNodeInserted", ...)
oder optimieren, indem Sie Daten wie folgt übergeben:
$(document.body).on("domNodeInserted", "select.test", {
attributes: true,
subtree: false
}, function () {
$(this).combobox();
});
Dies würde die Überprüfung des Erscheinungsbilds eines select.test
Elements auslösen, wenn sich Attribute für Elemente direkt im Körper ändern.
Sie können es live unten oder auf jsFiddle sehen .
(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>
Hinweis
Dieser jQuery-Code ist eine ziemlich einfache Implementierung. Es wird nicht ausgelöst, wenn Änderungen an anderer Stelle Ihren Selektor gültig machen.
Angenommen, Ihre Auswahl ist .test select
und das Dokument hat bereits eine <select>
. Durch Hinzufügen der Klasse test
zu <body>
wird der Selektor gültig, aber da ich nur record.target
und überprüfe record.addedNodes
, wird das Ereignis nicht ausgelöst. Die Änderung muss an dem Element erfolgen, das Sie selbst auswählen möchten.
Dies könnte vermieden werden, indem bei allen Mutationen nach dem Selektor gefragt wird. Ich habe mich dafür entschieden, dies nicht zu tun, um zu vermeiden, dass doppelte Elemente für Elemente verursacht werden, die bereits behandelt wurden. Der richtige Umgang mit benachbarten oder allgemeinen Geschwisterkombinatoren würde die Dinge noch schwieriger machen.
Für eine umfassendere Lösung finden https://github.com/pie6k/jquery.initialize , wie in erwähnt Damien Ó Ceallaigh ‚s Antwort . Der Autor dieser Bibliothek hat jedoch angekündigt, dass die Bibliothek alt ist, und schlägt vor, dass Sie dafür jQuery nicht verwenden sollten.
$(select).ready(function() { });