Je veux exécuter une fonction lorsqu'un div ou un input est ajouté au html. Est-ce possible ?
Par exemple, si une entrée de texte est ajoutée, la fonction doit être appelée.
Je veux exécuter une fonction lorsqu'un div ou un input est ajouté au html. Est-ce possible ?
Par exemple, si une entrée de texte est ajoutée, la fonction doit être appelée.
(IE9+, FF, Webkit)
Utilisation de MutationObserver et de revenir à la version obsolète Événements de mutation si nécessaire :
(Exemple ci-dessous si seulement pour les changements DOM concernant les noeuds ajoutés ou enlevés)
var observeDOM = (function(){
var MutationObserver = window.MutationObserver || window.WebKitMutationObserver;
return function( obj, callback ){
if( !obj || obj.nodeType !== 1 ) return;
if( MutationObserver ){
// define a new observer
var mutationObserver = new MutationObserver(callback)
// have the observer observe foo for changes in children
mutationObserver.observe( obj, { childList:true, subtree:true })
return mutationObserver
}
// browser support fallback
else if( window.addEventListener ){
obj.addEventListener('DOMNodeInserted', callback, false)
obj.addEventListener('DOMNodeRemoved', callback, false)
}
}
})()
//------------< DEMO BELOW >----------------
// add item
var itemHTML = "<li><button>list item (click to delete)</button></li>",
listElm = document.querySelector('ol');
document.querySelector('body > button').onclick = function(e){
listElm.insertAdjacentHTML("beforeend", itemHTML);
}
// delete item
listElm.onclick = function(e){
if( e.target.nodeName == "BUTTON" )
e.target.parentNode.parentNode.removeChild(e.target.parentNode);
}
// Observe a specific DOM element:
observeDOM( listElm, function(m){
var addedNodes = [], removedNodes = [];
m.forEach(record => record.addedNodes.length & addedNodes.push(...record.addedNodes))
m.forEach(record => record.removedNodes.length & removedNodes.push(...record.removedNodes))
console.clear();
console.log('Added:', addedNodes, 'Removed:', removedNodes);
});
// Insert 3 DOM nodes at once after 3 seconds
setTimeout(function(){
listElm.removeChild(listElm.lastElementChild);
listElm.insertAdjacentHTML("beforeend", Array(4).join(itemHTML));
}, 3000);
<button>Add Item</button>
<ol>
<li><button>list item (click to delete)</button></li>
<li><button>list item (click to delete)</button></li>
<li><button>list item (click to delete)</button></li>
<li><button>list item (click to delete)</button></li>
<li><em>…More will be added after 3 seconds…</em></li>
</ol>
Cela semble fonctionner assez bien pour les nouveaux noeuds DOM. Pouvons-nous l'adapter pour qu'il gère également les changements de nœuds DOM (au moins les valeurs/le texte du nœud DOM ?).
Cela m'a beaucoup aidé, mais comment puis-je le "délier" ? Disons que je veux surveiller un changement une seule fois, mais le faire à plusieurs reprises ? oberserveDOM = null ne fonctionnera évidemment pas...
MutationObserver
est prise en charge par les navigateurs modernes :Chrome 18+, Firefox 14+, IE 11+, Safari 6+.
Si vous devez soutenir les plus anciens, vous pouvez essayer de vous rabattre sur d'autres approches, comme celles mentionnées dans le présent document. 5 ( !) réponse d'un an ci-dessous. Il y a des dragons. Amusez-vous bien :)
Quelqu'un d'autre modifie le document ? Parce que si vous avez le contrôle total des modifications, il vous suffit de créer votre propre système de gestion des documents. domChanged
API - avec une fonction ou un événement personnalisé - et de le déclencher/appeler partout où vous modifiez les choses.
El Le niveau 2 de DOM a Types d'événements de mutation mais les anciennes versions d'IE ne le supportent pas. Notez que les événements de mutation sont déprécié dans la spécification DOM3 Events et avoir un pénalité de performance .
Vous pouvez essayer d'émuler l'événement de mutation avec onpropertychange
dans IE (et revenir à l'approche par la force brute si aucune d'entre elles n'est disponible).
Pour un complet domChange un intervalle pourrait être une surcharge. Imaginez que vous ayez besoin de stocker l'état actuel de l'ensemble du document, et d'examiner toutes les propriétés de chaque élément pour qu'elles soient identiques.
Peut-être que si vous ne vous intéressez qu'aux éléments et à leur ordre (comme vous l'avez mentionné dans votre question), une getElementsByTagName("*")
peut fonctionner. Cela se déclenchera automatiquement si vous ajoutez un élément, supprimez un élément, remplacez des éléments ou modifiez la structure du document.
J'ai écrit une preuve de concept :
(function (window) {
var last = +new Date();
var delay = 100; // default delay
// Manage event queue
var stack = [];
function callback() {
var now = +new Date();
if (now - last > delay) {
for (var i = 0; i < stack.length; i++) {
stack[i]();
}
last = now;
}
}
// Public interface
var onDomChange = function (fn, newdelay) {
if (newdelay) delay = newdelay;
stack.push(fn);
};
// Naive approach for compatibility
function naive() {
var last = document.getElementsByTagName('*');
var lastlen = last.length;
var timer = setTimeout(function check() {
// get current state of the document
var current = document.getElementsByTagName('*');
var len = current.length;
// if the length is different
// it's fairly obvious
if (len != lastlen) {
// just make sure the loop finishes early
last = [];
}
// go check every element in order
for (var i = 0; i < len; i++) {
if (current[i] !== last[i]) {
callback();
last = current;
lastlen = len;
break;
}
}
// over, and over, and over again
setTimeout(check, delay);
}, delay);
}
//
// Check for mutation events support
//
var support = {};
var el = document.documentElement;
var remain = 3;
// callback for the tests
function decide() {
if (support.DOMNodeInserted) {
window.addEventListener("DOMContentLoaded", function () {
if (support.DOMSubtreeModified) { // for FF 3+, Chrome
el.addEventListener('DOMSubtreeModified', callback, false);
} else { // for FF 2, Safari, Opera 9.6+
el.addEventListener('DOMNodeInserted', callback, false);
el.addEventListener('DOMNodeRemoved', callback, false);
}
}, false);
} else if (document.onpropertychange) { // for IE 5.5+
document.onpropertychange = callback;
} else { // fallback
naive();
}
}
// checks a particular event
function test(event) {
el.addEventListener(event, function fn() {
support[event] = true;
el.removeEventListener(event, fn, false);
if (--remain === 0) decide();
}, false);
}
// attach test events
if (window.addEventListener) {
test('DOMSubtreeModified');
test('DOMNodeInserted');
test('DOMNodeRemoved');
} else {
decide();
}
// do the dummy test
var dummy = document.createElement("div");
el.appendChild(dummy);
el.removeChild(dummy);
// expose
window.onDomChange = onDomChange;
})(window);
Utilisation :
onDomChange(function(){
alert("The Times They Are a-Changin'");
});
Cela fonctionne sur IE 5.5+, FF 2+, Chrome, Safari 3+ et Opera 9.6+.
Ne pouvons-nous pas ajouter un auditeur actif (je ne sais pas comment dire !) ou quelque chose qui vérifie l'intervalle et le domaine ?
Je me demande : comment jQuery live() résout-il ce problème s'il ne peut pas détecter un changement de DOM ?
L'exemple suivant a été adapté de Mozilla Hacks'. article de blog et utilise MutationObserver .
// Select the node that will be observed for mutations
var targetNode = document.getElementById('some-id');
// Options for the observer (which mutations to observe)
var config = { attributes: true, childList: true };
// Callback function to execute when mutations are observed
var callback = function(mutationsList) {
for(var mutation of mutationsList) {
if (mutation.type == 'childList') {
console.log('A child node has been added or removed.');
}
else if (mutation.type == 'attributes') {
console.log('The ' + mutation.attributeName + ' attribute was modified.');
}
}
};
// Create an observer instance linked to the callback function
var observer = new MutationObserver(callback);
// Start observing the target node for configured mutations
observer.observe(targetNode, config);
// Later, you can stop observing
observer.disconnect();
Navigateurs pris en charge : Chrome 18+, Firefox 14+, IE 11+, Safari 6+.
Ou vous pouvez simplement Créez votre propre événement qui courent partout
$("body").on("domChanged", function () {
//dom is changed
});
$(".button").click(function () {
//do some change
$("button").append("<span>i am the new change</span>");
//fire event
$("body").trigger("domChanged");
});
Exemple complet http://jsfiddle.net/hbmaam/Mq7NX/
Ce n'est pas la même chose... la méthode décrite ci-dessus est toujours valable api.jquery.com/trigger
J'ai récemment écrit un plugin qui fait exactement cela - jquery.initialize
Vous l'utilisez de la même manière que .each
fonction
$(".some-element").initialize( function(){
$(this).css("color", "blue");
});
La différence entre .each
est - il prend votre sélecteur, dans ce cas-ci .some-element
et attendre de nouveaux éléments avec ce sélecteur dans le futur, si un tel élément sera ajouté, il sera initialisé aussi.
Dans notre cas, la fonction initialize change juste la couleur de l'élément en bleu. Donc si nous ajoutons un nouvel élément (peu importe si c'est avec ajax ou même avec l'inspecteur F12 ou autre) comme :
$("<div/>").addClass('some-element').appendTo("body"); //new element will have blue color!
Le plugin l'initialisera instantanément. Le plugin s'assure également qu'un élément n'est initialisé qu'une seule fois. Ainsi, si vous ajoutez un élément, alors .detach()
et l'ajouter à nouveau, il ne sera pas initialisé à nouveau.
$("<div/>").addClass('some-element').appendTo("body").detach()
.appendTo(".some-container");
//initialized only once
Le plugin est basé sur MutationObserver
- il fonctionnera sur IE9 et 10 avec les dépendances telles que détaillées sur le site web de la Commission européenne. page readme .
Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.
1 votes
A moins qu'un script tiers ajoute les noeuds au DOM, ce n'est pas nécessaire.
0 votes
Duplicata de stackoverflow.com/questions/2457043/
0 votes
Duplicata possible de Existe-t-il un écouteur de changement de DOM JavaScript/jQuery ?
10 votes
@JustinJohnson si vous faites une extension chrome qui injecte du code JS, c'est utile.
0 votes
github.com/Maykonn/page-info-js
0 votes
Je ne comprends vraiment pas - c'est comme... eh... demander un réveil à l'hôtel au buffet du petit-déjeuner... Vous changez le DOM avec JS et ensuite vous voulez que les JS-events vous notifient de ce que vous venez de faire ? Cela ressemble à une base de code géniale. Si vous attendez simplement qu'un sélecteur css spécifique soit chargé, il existe des méthodes plus anciennes comme onload="", jquery .ready() ou une vérification manuelle de setInterval qui résout le problème sans un blob supplémentaire de 50kb comme les "solutions" ci-dessous. :P
0 votes
Vous supposez un scénario où seul votre propre code changera votre domaine. Imaginez un scénario où vous utilisez une bibliothèque tierce et où vous voulez savoir quand elle change le domaine. Il y a aussi beaucoup d'autres cas d'utilisation, c'est la raison pour laquelle nous avons maintenant le support de MutationObserver dans tous les navigateurs modernes.
0 votes
Voir : stackoverflow.com/questions/54112328/ et eager.io/blog/three-real-world-use-cases-for-mutation-observer