Saya ingin menjalankan fungsi ketika beberapa div atau input ditambahkan ke html. Apakah ini mungkin?
Misalnya, input teks ditambahkan, maka fungsinya harus dipanggil.
Saya ingin menjalankan fungsi ketika beberapa div atau input ditambahkan ke html. Apakah ini mungkin?
Misalnya, input teks ditambahkan, maka fungsinya harus dipanggil.
Jawaban:
MutationObserver
didukung oleh peramban modern:Chrome 18+, Firefox 14+, IE 11+, Safari 6+
Jika Anda perlu mendukung yang lebih lama, Anda dapat mencoba kembali ke pendekatan lain seperti yang disebutkan dalam jawaban 5 (!) Tahun di bawah ini. Ada naga. Nikmati :)
Orang lain mengganti dokumen? Karena jika Anda memiliki kontrol penuh atas perubahan, Anda hanya perlu membuat domChanged
API Anda sendiri - dengan fungsi atau acara khusus - dan memicu / menyebutnya di mana pun Anda memodifikasi sesuatu.
The DOM Level-2 memiliki Mutasi jenis acara , namun versi yang lebih tua dari IE tidak mendukung hal itu. Perhatikan bahwa peristiwa mutasi tidak lagi digunakan dalam spesifikasi Acara DOM3 dan memiliki penalti kinerja .
Anda dapat mencoba meniru acara mutasi dengan onpropertychange
di IE (dan kembali ke pendekatan brute-force jika tidak ada yang tersedia).
Untuk domChange penuh, interval bisa menjadi over-kill. Bayangkan Anda perlu menyimpan keadaan saat ini dari seluruh dokumen, dan memeriksa setiap properti setiap elemen menjadi sama.
Mungkin jika Anda hanya tertarik pada elemen dan urutannya (seperti yang Anda sebutkan dalam pertanyaan Anda), sebuah getElementsByTagName("*")
kaleng bisa berfungsi. Ini akan diaktifkan secara otomatis jika Anda menambahkan elemen, menghapus elemen, mengganti elemen atau mengubah struktur dokumen.
Saya menulis bukti konsep:
(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);
Pemakaian:
onDomChange(function(){
alert("The Times They Are a-Changin'");
});
Ini berfungsi pada IE 5.5+, FF 2+, Chrome, Safari 3+ dan Opera 9.6+
IE9 +, FF, Webkit:
Menggunakan MutationObserver dan kembali ke acara mutasi yang sudah tidak digunakan lagi jika diperlukan:
(Contoh di bawah ini hanya untuk perubahan DOM terkait dengan node yang ditambahkan atau dihapus)
var observeDOM = (function(){
var MutationObserver = window.MutationObserver || window.WebKitMutationObserver;
return function( obj, callback ){
if( !obj || !obj.nodeType === 1 ) return; // validation
if( MutationObserver ){
// define a new observer
var obs = new MutationObserver(function(mutations, observer){
callback(mutations);
})
// have the observer observe foo for changes in children
obs.observe( obj, { childList:true, subtree:true });
}
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>
mutations, observer
parameter ke fungsi panggilan balik untuk kontrol lebih lanjut.
Baru-baru ini saya menulis sebuah plugin yang melakukan hal itu - jquery.initialize
Anda menggunakannya dengan cara yang sama seperti .each
fungsi
$(".some-element").initialize( function(){
$(this).css("color", "blue");
});
Perbedaannya .each
adalah - dibutuhkan pemilih Anda, dalam hal ini .some-element
dan menunggu elemen baru dengan pemilih ini di masa mendatang, jika elemen tersebut akan ditambahkan, ia akan diinisialisasi juga.
Dalam kasus kami, inisialisasi fungsi hanya mengubah warna elemen menjadi biru. Jadi jika kita akan menambahkan elemen baru (tidak peduli apakah dengan ajax atau bahkan inspektur F12 atau apa pun) seperti:
$("<div/>").addClass('some-element').appendTo("body"); //new element will have blue color!
Plugin akan langsung melakukannya. Plugin juga memastikan satu elemen diinisialisasi hanya sekali. Jadi jika Anda menambahkan elemen, maka .detach()
dari tubuh dan kemudian menambahkannya lagi, itu tidak akan diinisialisasi lagi.
$("<div/>").addClass('some-element').appendTo("body").detach()
.appendTo(".some-container");
//initialized only once
Plugin didasarkan pada MutationObserver
- itu akan bekerja pada IE9 dan 10 dengan dependensi seperti yang dirinci pada halaman readme .
atau Anda cukup Buat acara Anda sendiri , yang berjalan di mana-mana
$("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");
});
Contoh lengkap http://jsfiddle.net/hbmaam/Mq7NX/
Ini adalah contoh menggunakan MutationObserver dari Mozilla yang diadaptasi dari posting blog ini
Chrome 18+, Firefox 14+, IE 11+, Safari 6+
// 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();
Gunakan antarmuka MutationObserver seperti yang ditunjukkan di blog Gabriele Romanato
Chrome 18+, Firefox 14+, IE 11+, Safari 6+
// The node to be monitored
var target = $( "#content" )[0];
// Create an observer instance
var observer = new MutationObserver(function( mutations ) {
mutations.forEach(function( mutation ) {
var newNodes = mutation.addedNodes; // DOM NodeList
if( newNodes !== null ) { // If there are new nodes added
var $nodes = $( newNodes ); // jQuery set
$nodes.each(function() {
var $node = $( this );
if( $node.hasClass( "message" ) ) {
// do something
}
});
}
});
});
// Configuration of the observer:
var config = {
attributes: true,
childList: true,
characterData: true
};
// Pass in the target node, as well as the observer options
observer.observe(target, config);
// Later, you can stop observing
observer.disconnect();
Bagaimana kalau memperpanjang jquery untuk ini?
(function () {
var ev = new $.Event('remove'),
orig = $.fn.remove;
var evap = new $.Event('append'),
origap = $.fn.append;
$.fn.remove = function () {
$(this).trigger(ev);
return orig.apply(this, arguments);
}
$.fn.append = function () {
$(this).trigger(evap);
return origap.apply(this, arguments);
}
})();
$(document).on('append', function (e) { /*write your logic here*/ });
$(document).on('remove', function (e) { /*write your logic here*/ ) });
Jquery 1.9+ telah membangun dukungan untuk ini (saya dengar belum diuji).