MutationObserver 㯠DOM è¦ç´ ãç£è¦ãã夿´ããã£ãå ´åã«ã³ã¼ã«ããã¯ãèµ·åããçµã¿è¾¼ã¿ã®ãªãã¸ã§ã¯ãã§ãã
æåã«æ§æã確èªãã¦ãããå®éã®ã¦ã¼ã¹ã±ã¼ã¹ãè¦ã¦ããã¾ãããã
æ§æ
MutationObserver ã¯ç°¡åã«ä½¿ç¨ã§ãã¾ãã
ã¾ããã³ã¼ã«ããã¯é¢æ°ã弿°ã«ãã¤ãªãã¶ã¼ã(observer)ã使ãã¾ãã:
let observer = new MutationObserver(callback);
次ã«ãDOM ãã¼ãã«ã¢ã¿ãããã¾ãã:
observer.observe(node, config);
config ã¯ãã¼ã«å¤ã®ãªãã·ã§ã³ãæã¤ãªãã¸ã§ã¯ãã§ãâã©ã®ç¨®é¡ã®å¤æ´ã«åå¿ãããâ ãæå®ãã¾ãã:
childListânodeã®ç´æ¥ã®åã®å¤æ´,subtreeânodeã®ãã¹ã¦ã®åå«ã«å¯¾ãã夿´,attributesânodeã®å±æ§ã®å¤æ´,attributeFilterâ æå®ãããã®ã ããç£è¦ããããã®ã屿§ã®é åcharacterDataânode.data(ããã¹ãã³ã³ãã³ã) ãç£è¦ãããã©ãã,
ã»ãã«ãããã¤ãã®ãªãã·ã§ã³ãããã¾ã:
attributeOldValueâtrueã®å ´åãã³ã¼ã«ããã¯ã«å±æ§ã®æ°æ§ä¸¡æ¹ã®å¤ã渡ãã¾ããããã§ãªããã°ãæ°ãããã®ã®ã¿ã渡ãã¾ãï¼attributesãªãã·ã§ã³ãå¿ è¦ã§ãï¼,characterDataOldValueâtrueã®å ´åãã³ã¼ã«ããã¯ã«node.dataã®æ°æ§ä¸¡æ¹ã®å¤ã渡ãã¾ããããã§ãªããã°ãæ°ãããã®ã®ã¿ã渡ãã¾ãï¼characterDataãªãã·ã§ã³ãå¿ è¦ã§ãï¼,
ãã®å¾ãä»»æã®å¤æ´å¾ã« callback ãå®è¡ããã¾ãããã®éãæåã®å¼æ°ã«ã¯ MutationRecord ãªãã¸ã§ã¯ãã®ãªã¹ãã2 çªç®ã®å¼æ°ã«ã¯ããªãã¶ã¼ãèªä½ãä¸ãããã¾ãã
MutationRecord ãªãã¸ã§ã¯ãã¯æ¬¡ã®ããããã£ãæã£ã¦ãã¾ã:
typeâ mutation(å¤å)ã®ç¨®é¡, 次ã®ããããã§ãã"attributes"(屿§ã夿´ããã)"characterData"(ãã¼ã¿ã夿´ããã)"childList"(è¦ç´ ã追å /åé¤ããã),
targetâ 夿´ãèµ·ãã£ãå ´æ: âattributesâ ã®å ´åã¯è¦ç´ , âcharacterDataâ ã®å ´åã¯ããã¹ããã¼ã, ããã㯠âchildListâ ã®å¤åã®å ´åã¯è¦ç´ ã§ã,addedNodes/removedNodesâ 追å /åé¤ããããã¼ã,previousSibling/nextSiblingâ 追å /åé¤ããããã¼ãã®åå¾ã®å å¼,attributeName/attributeNamespaceâ 夿´ããã屿§ã®åå/ãã¼ã ã¹ãã¼ã¹ (XML ã®å ´å),oldValueâ 以åã®å¤ã屿§ãããã¯ããã¹ãã®å¤æ´ã®å ´åã®ã¿ï¼å¯¾å¿ãããªãã·ã§ã³attributeOldValue/characterDataOldValueãè¨å®ããã¦ããå ´åï¼
ä¾ãã°ãããã«ã¯ contentEditable 屿§ãã㤠<div> ãããã¾ãããã®å±æ§ãæå®ããã¨ããã©ã¼ã«ã¹ããã¨ç·¨éãããã¨ãã§ãã¾ãã
<div contentEditable id="elem">Click and <b>edit</b>, please</div>
<script>
let observer = new MutationObserver(mutationRecords => {
console.log(mutationRecords); // console.log(the changes)
});
// 屿§ä»¥å¤ã®ãã¹ã¦ãç£è¦ãã
observer.observe(elem, {
childList: true, // ç´æ¥ã®åãç£è¦ãã
subtree: true, // åå«ãã¡ã
characterDataOldValue: true // ã³ã¼ã«ããã¯ã«å¤ãå¤ã渡ã
});
</script>
ãã©ã¦ã¶ã§å®è¡ãã<div> ã«ãã©ã¼ã«ã¹ã <b>edit</b> å
ã®ããã¹ãã夿´ããã¨ãconsole.log ã« mutation(å¤å)ã表示ããã¾ã:
mutationRecords = [{
type: "characterData",
oldValue: "edit",
target: <text node>,
// ä»ã®ããããã£ã¯ç©ºã§ã
}];
ããè¤éãªç·¨éæä½ãè¡ã£ãå ´åãä¾ãã° <b>edit</b> ãåé¤ããã¨ãmutation ã¤ãã³ãã¯è¤æ°ã® mutation records ãå«ã¿ã¾ã:
mutationRecords = [{
type: "childList",
target: <div#elem>,
removedNodes: [<b>],
nextSibling: <text node>,
previousSibling: <text node>
// ä»ã®ããããã£ã¯ç©ºã§ã
}, {
type: "characterData"
target: <text node>
// ...詳細ã¯ããã©ã¦ã¶ãã©ã®ããã«å¤æ´ãå¦çãããã«ãã£ã¦ç°ãªãã¾ãã
// 2ã¤ã®é£æ¥ãããã¼ã "Edit " 㨠", please" ã1ã¤ã®ãã¼ãã«åä½ããããããã¾ããã
// ãããã¯ãåã« "Edit" ã®å¾ã®ä½åãªã¹ãã¼ã¹ãåé¤ããå¯è½æ§ãããã¾ãã
}];
ãããã£ã¦ãMutationObserver ã§ DOMãµãããªã¼å
ã®ä»»æã®å¤æ´ã«åå¿ãããã¨ãã§ãã¾ãã
çµ±åããããã®ä½¿ç¨æ³
ã㤠MutationObserver ãå¿
è¦ã§ããããï¼
便å©ãªæ©è½ãå«ãã§ããããä¾ãã°åºå <div class="ads">Unwanted ads</div> ã表示ããã¨ãã£ã好ã¾ãããªããã¨ãè¡ãã3rdãã¼ãã£ã®ã¹ã¯ãªããã追å ããå¿
è¦ãããã±ã¼ã¹ãæ³åãã¦ãã ããã
ãã¡ããã3rd ãã¼ãã£ã®ã¹ã¯ãªããã«ã¯ãåºåãåé¤ããä»çµã¿ã¯æä¾ããã¦ãã¾ããã
MutationObserver ã使ç¨ãããã¨ã§ã好ã¾ãããªãè¦ç´ ã DOM ã«è¡¨ç¤ºãããå ´åã«ãããæ¤ç¥ããåé¤ãããã¨ãã§ãã¾ãã
å¥ã®ç¶æ³ã¨ãã¦ã¯ã3rd ãã¼ãã£ã®ã¹ã¯ãªãããæã ã®ããã¥ã¡ã³ãã«ä½ãã追å ããéã«ããããæ¤åºããåçã«ãªãµã¤ãºãããªã©ãã¼ã¸ã«é©åããããå ´åãèãããã¾ãã
MutationObserver ã使ç¨ããã¨ããããå®è£
ãããã¨ãã§ãã¾ãã
ã¢ã¼ããã¯ãã£ã®ããã®ä½¿ç¨æ³
ã¾ããMutationObserver ãã¢ã¼ããã¯ãã£ã®è¦³ç¹ããè¦ã¦è¯ãç¶æ³ãããã¾ãã
ä¾ãã°ãããã°ã©ãã³ã°ã«é¢ãã Web ãµã¤ãã使ãã¦ããã¨ãã¾ããããå½ç¶ãªãããè¨äºããã®ä»ã®è³æã«ã¯ã½ã¼ã¹ã³ã¼ãã®ã¹ãããããå«ã¾ãããã¨ãããã¾ãã
HTML ãã¼ã¯ã¢ããã§ãã®ãããªã¹ããããã¯æ¬¡ã®ããã«ãªãã¾ã:
...
<pre class="language-javascript"><code>
// ããã«ã³ã¼ã
let hello = "world";
</code></pre>
...
ããèªã¿ãããããã¨åæã«ãããç¾ããããããã«ãPrism.js ã®ãããªãJavaScript ã®ã·ã³ã¿ãã¯ã¹ãã¤ã©ã¤ãã©ã¤ãã©ãªã使ç¨ãã¾ããPrism ã§ä¸è¨ã®ãããªã¹ãããããã·ã³ã¿ãã¯ã¹ãã¤ã©ã¤ãããã«ã¯ãPrism.highlightElem(pre) ãå¼ã°ããpre è¦ç´ ã®å
å®¹ãæ¤æ»ãããããã®ãã¼ã¸ã®ä¾ã¨åãããã«ãè²ä»ãã®æ§æãã¤ã©ã¤ãã追å ããã¾ãã
å
·ä½çã«ã¯ãã¤ãã¤ã©ã¤ããè¡ãã¡ã½ãããå®è¡ãã¹ãã§ããããï¼DOMContentLoaded ã¤ãã³ãããããã¯ããã¼ã¸ã®æ«å°¾ã«ã¹ã¯ãªãããé
ç½®ãããã¨ã§ãã¤ã©ã¤ããã§ãã¾ããDOM ãæºåã§ããæç¹ã§ãpre[class*="language"] ãæ¢ããããã«å¯¾ã㦠Prism.highlightElem ãå¼ã³åºããã¨ãå¯è½ã§ã:
// ãã¼ã¸ä¸ã®ãã¹ã¦ã®ã³ã¼ãã¹ããããããã¤ã©ã¤ã表示ãã
document.querySelectorAll('pre[class*="language"]').forEach(Prism.highlightElem);
ä»ã®ã¨ããããã¹ã¦ç°¡åã§ãããHTML ä¸ã« <pre> ã®ã³ã¼ãã¹ãããããããããããããã¤ã©ã¤ã表示ãã¦ãã¾ãã
ã§ã¯ç¶ãã¾ãããããµã¼ãããè³æãç´ æãåçã«åå¾ããã¨ãã¾ããç§ãã¡ã¯ãè¨äº "fetch-basics" ãè¦ã¤ããã¾ããã§ãã®ããã®ã¡ã½ãããå¦ã³ã¾ããããã§ã¯ãWeb ãµã¼ããã HTML ã®è¨äºãåå¾ãããªã³ããã³ãã§ããã表示ãããã¨ããç¹ããã¤ã³ãã§ãã:
let article = /* ãµã¼ãããæ°ããã³ã³ãã³ããåå¾ãã */
articleElem.innerHTML = article;
æ°ãã article HTML ã¯ã³ã¼ãã¹ãããããå«ãããããã¾ããããããã«å¯¾ã㦠Prism.highlightElem ãå¼ã³åºãå¿
è¦ãããã¾ããããããªãã¨ããã¤ã©ã¤ã表示ããã¾ããã
åçã«ãã¼ããããè¨äºã«å¯¾ãã¦ãã¤ãã©ãã§ Prism.highlightElem ãå¼ã³åºãã§ããããï¼
次ã®ããã«ãè¨äºããã¼ãããã³ã¼ãã¸ãã®å¼ã³åºãã追å ãããã¨ã¯ã§ãã¾ãã:
let article = /* ãµã¼ãããæ°ããã³ã³ãã³ããåå¾ãã */
articleElem.innerHTML = article;
let snippets = articleElem.querySelectorAll('pre[class*="language-"]');
snippets.forEach(Prism.highlightElem);
â¦ãããæ³åãã¦ã¿ã¦ãã ãããã³ã¼ãã§ã³ã³ãã³ãããã¼ãããå ´æã¯ããããããã¾ãã: è¨äºã質åããã©ã¼ã©ã ã¸ã®æç¨¿ãªã©ãå°ãã¨ããã«ãã¤ã©ã¤ã表示ãããå¼ã³åºããæ¸ããªããã°ãªããªãã®ã§ããããï¼ã¾ãããã®å¼ã³åºããå¿ããªãããã«æ³¨æããå¿ è¦ãããã¾ãã
ã¾ããä»®ã«ã³ã³ãã³ãããµã¼ããã¼ãã£ã®ã¨ã³ã¸ã³ã«ãã¼ãããå ´åã¯ã©ããªãã§ãããï¼E.g. 誰ãã«ãã£ã¦æ¸ããããã©ã¼ã©ã ããããããã¯åçã«ã³ã³ãã³ãããã¼ããã¾ããããã¦ãããã«æ§æã®ãã¤ã©ã¤ã表示ã追å ããããããªå ´åã§ãã誰ããµã¼ããã¼ãã£ã®ã¹ã¯ãªããã«ããããå½ã¦ããããªãã¨ã¯ãããããã¾ããã
幸ããªãã¨ã«ãå¥ã®é¸æè¢ãããã¾ãã
ãã¼ã¸ã«æ¿å
¥ãããã³ã¼ãã¹ãããããèªåã§æ¤åºãããããããã¤ã©ã¤ã表示ããããã«ãMutationObserver ã使ãã¾ãã
ããã«ãããç§ãã¡ã¯ãã¤ã©ã¤ãæ©è½ãä¸ã¶æã§å¦çãããã¨ãã§ããçµ±åã®å¿ è¦æ§ããè§£æ¾ããã¾ãã
åçãªãã¤ã©ã¤ã表示ã®ãã¢
ããã«åä½ãµã³ãã«ãããã¾ãã
ã³ã¼ããå®è¡ããã¨ãä¸ã®è¦ç´ ãç£è¦ãå§ããããã«è¡¨ããä»»æã®ã³ã¼ãã¹ããããããã¤ã©ã¤ã表示ãã¾ãã:
let observer = new MutationObserver(mutations => {
for(let mutation of mutations) {
// æ°ãããã¼ããæ¤æ»ãããã¤ã©ã¤ããããã®ã¯ãããï¼
for(let node of mutation.addedNodes) {
// è¦ç´ ã®ã¿ã追跡ããä»ã®ãã¼ãï¼ä¾ ããã¹ããã¼ãï¼ã¯ã¹ããããã¾ã
if (!(node instanceof HTMLElement)) continue;
// æ¿å
¥ãããè¦ç´ ãã³ã¼ãã¹ããããã§ãããããã§ãã¯ãã¾ã
if (node.matches('pre[class*="language-"]')) {
Prism.highlightElement(node);
}
// ãããã¯ããµãããªã¼ã®ã©ããã«ã³ã¼ãã¹ããããããããï¼
for(let elem of node.querySelectorAll('pre[class*="language-"]')) {
Prism.highlightElement(elem);
}
}
}
});
let demoElem = document.getElementById('highlight-demo');
observer.observe(demoElem, {childList: true, subtree: true});
ããã§ã以ä¸ã«ã¯ HTMLè¦ç´ ã¨ãinnterHTML ã使ç¨ãã¦åçã«ãããåããJavaScript ãããã¾ãã
åã®ã³ã¼ãï¼ä¸è¨ãè¦ç´ ãç£è¦ãã¾ãï¼ããã®å¾ä¸ã®ã³ã¼ããå®è¡ãã¦ã¿ã¦ãã ãããMutationObserver ãã©ã®ããã«ã¹ãããããæ¤åºãããã¤ã©ã¤ãããã®ãã確èªã§ãã¾ãã
id="highlight-demo"ãæã¤ãã¢è¦ç´ ã§ããä¸ã®ãµã³ãã«ã§ç£è¦ããã¦ãã¾ãã
以ä¸ã®ã³ã¼ã㯠innerHTML ã§ãã¼ã¿ãè¨å®ãã¾ããããä¸ã®ã³ã¼ããå®è¡ãã¦ããã°ãã¹ããããããã¤ã©ã¤ã表示ããã¾ãã:
let demoElem = document.getElementById('highlight-demo');
// ã³ã¼ãã¹ãããããæã¤ã³ã³ãã³ããåçã«æ¿å
¥ãã
demoElem.innerHTML = `A code snippet is below:
<pre class="language-javascript"><code> let hello = "world!"; </code></pre>
<div>Another one:</div>
<div>
<pre class="language-css"><code>.class { margin: 5px; } </code></pre>
</div>
`;
ããã§ãç£è¦ãããè¦ç´ ã¾ã㯠document å
¨ä½ã®ãã¹ã¦ã®ãã¤ã©ã¤ã表示ã追跡ã§ãã MutationObserver ãã§ãã¾ãããããã«ã¤ãã¦èãããã¨ãªããã³ã¼ãã¹ããããã®è¿½å /åé¤ãã§ãã¾ãã
追å ã®ã¡ã½ãã
ãã¼ãã®ç£è¦ã忢ããããã®ã¡ã½ãããããã¾ã:
observer.disconnect()â ç£è¦ãããã¾ã
ç£è¦ã忢ããã¨ãããªãã¶ã¼ãã«ããã¾ã å¦çããã¦ããªã夿´ãããå¯è½æ§ãããã¾ãããã®ãããªå ´åã¯ä»¥ä¸ã使ç¨ãã¾ã
observer.takeRecords()â æªå¦çã® mutation(å¤å)ã®ã¬ã³ã¼ãä¸è¦§ãåå¾ãã¾ãããããã¯ãå¤åã¯çºçããããã³ã¼ã«ããã¯ã¯ããããå¦çããªãã£ããã®ã§ãã
ãããã®ã¡ã½ããã¯æ¬¡ã®ããã«ä¸ç·ã«ä½¿ç¨ããã¾ã:
// æªå¦çã® mutation ã®ä¸è¦§ãåå¾ãã¾ã
// å¦çãããªãå¯è½æ§ã®ããæè¿ã®å¤æ´ãèæ
®ããå ´å
// disconnect ã®åã«å¼ã¶å¿
è¦ãããã¾ã
let mutationRecords = observer.takeRecords();
// 夿´ã®è¿½è·¡ãã¹ããããã¾ã
observer.disconnect();
...
observer.takeRecords() ã§è¿å´ãããã¬ã³ã¼ãã¯ãå¦çãã¥ã¼ããåé¤ããã¾ãobserver.takeRecords() ã§è¿å´ãããã¬ã³ã¼ãã«å¯¾ããã³ã¼ã«ããã¯ã¯å¼ã°ãã¾ããã
å é¨çã«ããªãã¶ã¼ãã¯ãã¼ãã«å¯¾ãã¦å¼±ãåç §ã使ç¨ãã¾ããã¤ã¾ãããã¼ããDOMããåé¤ãããå°éä¸å¯è½ã«ãªãã¨ãã¬ãã¼ã¸ã³ã¬ã¯ã·ã§ã³ã®å¯¾è±¡ã¨ãªããã¾ãã
DOM ãã¼ãã観測ãããã¨ããäºå®ã ãã§ã¯ãã¬ãã¼ã¸ã³ã¬ã¯ã·ã§ã³ãé²ããã¨ã¯ã§ãã¾ããã
ãµããª
MutationObserver 㯠DOM ã®å¤æ´ã«åå¿ãããã¨ãã§ãã¾ã: 屿§ãè¦ç´ ã®è¿½å /åé¤ãããã¹ãã³ã³ãã³ãã
ããã使ã£ã¦ãç§ãã¡èªèº«ã®ä»ã®é¨åã®ã³ã¼ããããã㯠3rd ãã¼ãã£ã®ã³ã¼ãã«ãã£ã¦ãããããã夿´ã追跡ãããã¨ãã§ãã¾ãã
MutationObserver ã¯ä»»æã®å¤æ´ã追跡å¯è½ã§ããâä½ãç£è¦ãããâ ãªãã·ã§ã³ã®è¨å®ã¯æé©åã®ããã«ä½¿ç¨ãããä¸è¦ãªã³ã¼ã«ããã¯ã®å¼ã³åºãã«ãªã½ã¼ã¹ãè²»ãããã¨ã¯ããã¾ããã
ã³ã¡ã³ã
<code>ã¿ã°ã使ã£ã¦ãã ãããè¤æ°è¡ã®å ´åã¯<pre>ãã10è¡ãè¶ ããå ´åã«ã¯ãµã³ãããã¯ã¹ã使ã£ã¦ãã ãã(plnkr, JSBin, codepenâ¦)ã