다른 여러 답변에서 언급했듯이 돌연변이 이벤트 는 더 이상 사용되지 않으므로 MutationObserver 를 사용해야합니다. 대신 를 합니다. 아직 아무도 그것에 대해 자세히 설명하지 않았기 때문에 여기에 간다 ...
기본 JavaScript API
MutationObserver 용 API는 매우 간단합니다. 돌연변이 사건만큼 간단하지는 않지만 여전히 괜찮습니다.
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>
그것을 분해합시다.
var observer = new MutationObserver(callback);
이것은 관찰자를 만듭니다. 관찰자는 아직 아무것도보고 있지 않습니다. 이것은 이벤트 리스너가 연결되는 곳입니다.
observer.observe(targetNode, { childList: true, subtree: true });
이렇게하면 관찰자가 시작됩니다. 첫 번째 인수는 관찰자가 변경 사항을 감시 할 노드입니다. 두 번째 인수는 감시 대상에 대한 옵션입니다 .
childList
추가되거나 제거되는 자식 요소를보고 싶다는 의미입니다.
subtree
이 요소의 하위 트리 어디에서나 변경 사항을 감시 하도록 확장 되는 수정 자입니다 childList
(그렇지 않으면에서 직접 변경 사항을 확인합니다 targetNode
).
그 외의 다른 두 가지 주요 옵션 childList
은 attributes
및 characterData
입니다. 이 세 가지 중 하나를 사용해야합니다.
function callback(records) {
records.forEach(function (record) {
콜백 내부에서 상황이 조금 까다로워집니다. 콜백은 MutationRecord 배열을 수신합니다 . 각 MutationRecord 한 유형의 몇 가지 변화를 설명 할 수 있습니다 ( childList
, attributes
또는 characterData
). 관찰자에게를 보라고 만 말 childList
했으므로 유형을 확인하지 않겠습니다.
var list = record.addedNodes;
여기에서 추가 된 모든 자식 노드의 NodeList를 가져옵니다. 노드가 추가되지 않은 모든 레코드에 대해 비어 있습니다 (이러한 레코드가 많을 수 있음).
거기에서 추가 된 노드를 반복하고 <select>
요소 인 .
여기에 정말 복잡한 것은 없습니다.
jQuery
...하지만 jQuery를 요청했습니다. 좋아.
(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);
이렇게하면 jQuery 특수 이벤트 API를domNodeInserted
사용하여 라는 새 이벤트가 생성 됩니다 . 다음과 같이 사용할 수 있습니다.
$(document).on("domNodeInserted", "select", function () {
$(this).combobox();
});
일부 라이브러리는 select
테스트 목적으로 요소를 생성하기 때문에 개인적으로 클래스를 찾는 것이 좋습니다 .
당연히 다음 .off("domNodeInserted", ...)
과 같은 데이터를 전달하여 시청을 사용 하거나 미세 조정할 수도 있습니다 .
$(document.body).on("domNodeInserted", "select.test", {
attributes: true,
subtree: false
}, function () {
$(this).combobox();
});
이렇게 select.test
하면 본문 내부의 요소에 대한 속성이 변경 될 때마다 요소 의 모양을 확인합니다 .
아래 또는 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>
노트
이 jQuery 코드는 상당히 기본적인 구현입니다. 다른 곳에서 수정하여 선택기를 유효하게 만드는 경우에는 트리거되지 않습니다.
예를 들어 선택기가이고 .test select
문서에 이미 <select>
. 에 클래스 test
를 추가하면 <body>
선택기가 유효하지만 record.target
및 만 확인하기 때문에 record.addedNodes
이벤트가 발생하지 않습니다. 선택하려는 요소가 변경되어야합니다.
이것은 변이가 발생할 때마다 선택자를 쿼리하여 피할 수 있습니다. 이미 처리 된 요소에 대해 중복 이벤트가 발생하지 않도록하기 위해 그렇게하지 않기로 결정했습니다. 인접 하거나 일반적인 형제 결합 자를 올바르게 처리 하면 상황이 더욱 까다로워집니다.
보다 포괄적 인 솔루션 은 Damien Ó Ceallaigh 의 답변 에서 언급했듯이 https://github.com/pie6k/jquery.initialize를 참조 하십시오 . 그러나 해당 라이브러리의 작성자는 라이브러리가 오래되었다고 발표했으며이를 위해 jQuery를 사용하지 말 것을 제안했습니다.
$(select).ready(function() { });