他のいくつかの回答で述べたように、ミューテーションイベントは非推奨になっているため、代わりにMutationObserverを使用する必要があります。まだ誰もそれについての詳細を与えていないので、ここに行きます...
基本的なJavaScriptAPI
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 });
これにより、オブザーバーが起動します。最初の引数は、オブザーバーが変更を監視するノードです。2番目の引数は、何を監視するかについてのオプションです。
childList
子要素が追加または削除されるのを監視したいという意味です。
subtree
は、この要素のサブツリー内の任意の場所で変更を監視するように拡張 する修飾子ですchildList
(それ以外の場合は、内の変更を直接確認しますtargetNode
)。
他の二つの主要なオプションがほかにchildList
あるattributes
とcharacterData
、彼らはのように聞こえるかについて平均います。これら3つのうちの1つを使用する必要があります。
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);
これによりdomNodeInserted
、jQueryの特別なイベントAPIを使用して、という新しいイベントが作成されます。あなたはそれを次のように使うことができます:
$(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() { });