Tôi muốn thực thi một chức năng khi một số div hoặc đầu vào được thêm vào html. Điều này có thể không?
Ví dụ, một đầu vào văn bản được thêm vào, sau đó chức năng sẽ được gọi.
Tôi muốn thực thi một chức năng khi một số div hoặc đầu vào được thêm vào html. Điều này có thể không?
Ví dụ, một đầu vào văn bản được thêm vào, sau đó chức năng sẽ được gọi.
Câu trả lời:
MutationObserver
được hỗ trợ bởi các trình duyệt hiện đại:Chrome 18+, Firefox 14+, IE 11+, Safari 6+
Nếu bạn cần hỗ trợ những người lớn tuổi hơn, bạn có thể cố gắng quay trở lại các phương pháp khác như phương pháp được đề cập trong câu trả lời 5 tuổi (!) Dưới đây. Có rồng. Thưởng thức :)
Một người khác đang thay đổi tài liệu? Bởi vì nếu bạn có toàn quyền kiểm soát các thay đổi, bạn chỉ cần tạo domChanged
API của riêng mình - với một chức năng hoặc sự kiện tùy chỉnh - và kích hoạt / gọi nó ở mọi nơi bạn sửa đổi mọi thứ.
Các DOM Level-2 có loại sự kiện đột biến , nhưng phiên bản cũ của trình duyệt IE không hỗ trợ nó. Lưu ý rằng các sự kiện đột biến không được chấp nhận trong thông số Sự kiện DOM3 và có hình phạt về hiệu suất .
Bạn có thể thử mô phỏng sự kiện đột biến bằng onpropertychange
IE (và quay lại cách tiếp cận vũ phu nếu không có sẵn chúng).
Đối với một domChange đầy đủ, một khoảng có thể là một giết quá mức. Hãy tưởng tượng rằng bạn cần lưu trữ trạng thái hiện tại của toàn bộ tài liệu và kiểm tra mọi thuộc tính của mọi thành phần đều giống nhau.
Có lẽ nếu bạn chỉ quan tâm đến các yếu tố và thứ tự của chúng (như bạn đã đề cập trong câu hỏi của bạn), thì getElementsByTagName("*")
có thể hoạt động. Điều này sẽ tự động kích hoạt nếu bạn thêm một phần tử, loại bỏ một phần tử, thay thế các phần tử hoặc thay đổi cấu trúc của tài liệu.
Tôi đã viết một bằng chứng về khái niệm:
(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);
Sử dụng:
onDomChange(function(){
alert("The Times They Are a-Changin'");
});
Điều này hoạt động trên IE 5.5+, FF 2+, Chrome, Safari 3+ và Opera 9.6+
IE9 +, FF, Webkit:
Sử dụng MutingObserver và quay lại các sự kiện Đột biến không dùng nữa nếu cần:
(Ví dụ bên dưới nếu chỉ thay đổi DOM liên quan đến các nút được nối hoặc xóa)
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
tham số cho chức năng gọi lại để kiểm soát nhiều hơn.
Gần đây tôi đã viết một plugin thực hiện chính xác điều đó - jquery.initialize
Bạn sử dụng nó giống như .each
chức năng
$(".some-element").initialize( function(){
$(this).css("color", "blue");
});
Sự khác biệt .each
là - nó sẽ chọn bộ chọn của bạn, trong trường hợp này .some-element
và chờ đợi các phần tử mới với bộ chọn này trong tương lai, nếu phần tử đó sẽ được thêm vào, nó cũng sẽ được khởi tạo.
Trong trường hợp của chúng tôi, chức năng khởi tạo chỉ cần thay đổi màu phần tử thành màu xanh. Vì vậy, nếu chúng tôi sẽ thêm phần tử mới (bất kể là với ajax hay thậm chí là thanh tra F12 hay bất cứ thứ gì) như:
$("<div/>").addClass('some-element').appendTo("body"); //new element will have blue color!
Plugin sẽ khởi tạo nó ngay lập tức. Ngoài ra plugin đảm bảo một yếu tố được khởi tạo chỉ một lần. Vì vậy, nếu bạn thêm phần tử, sau đó .detach()
nó từ phần thân và sau đó thêm phần tử đó , nó sẽ không được khởi tạo lại.
$("<div/>").addClass('some-element').appendTo("body").detach()
.appendTo(".some-container");
//initialized only once
Plugin dựa trên MutationObserver
- nó sẽ hoạt động trên IE9 và 10 với các phụ thuộc như chi tiết trên trang readme .
hoặc bạn có thể chỉ cần tạo sự kiện của riêng bạn , diễn ra ở mọi nơi
$("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");
});
Ví dụ đầy đủ http://jsfiddle.net/hbmaam/Mq7NX/
Đây là một ví dụ sử dụng MutingObserver từ Mozilla được điều chỉnh từ bài đăng trên blog này
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();
Sử dụng các MutationObserver giao diện như trong Gabriele Romanato của diễn đàn
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();
Làm thế nào về việc mở rộng một jquery cho điều này?
(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+ đã xây dựng hỗ trợ cho việc này (Tôi đã nghe nói chưa được thử nghiệm).