nextSibling による探索
特定の要素からみて、最初の子要素を取得する方法の nextSibling を試してみます。
まずは、前回と同様のHTMLを用意しました。
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <title>テストHTML</title> </head> <body> <div id="test1"> <div id="p1">p1text</div> <div id="p2">p2text <div id="c1">c1text</div> <div id="c2">c2text</div> <div id="c3">c3text</div> </div> <div id="p3">p3text <div id="d1">d1text</div> <div id="d2">d2text</div> <div id="d3">d3text</div> <div id="d4">d4text</div> </div> </div> </body> </html>
このHTMLに対して、idがp2のdivタグを親として、子要素をfirstChildを使って取得してみます。
下記のようにjavascriptを追記しました。
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <title>テストHTML</title> </head> <body> <div id="test1"> <div id="p1">p1text</div> <div id="p2">p2text <div id="c1">c1text</div> <div id="c2">c2text</div> <div id="c3">c3text</div> </div> <div id="p3">p3text <div id="d1">d1text</div> <div id="d2">d2text</div> <div id="d3">d3text</div> <div id="d4">d4text</div> </div> </div> <script type="text/javascript"> let c1 = document.getElementById("c1"); console.log("c1.nextSibling -> " + c1.nextSibling); // 「c1.nextSibling」の内容を確認する for(var key in c1.nextSibling){ console.log(key + " : " + c1.nextSibling[key]); } </script> </body> </html>
この結果、開発ツールのログには、以下のように出力されます。
c1.nextSibling -> [object Text] wholeText : assignedSlot : null splitText : function splitText() { [native code] } data : length : 3 previousElementSibling : [object HTMLDivElement] nextElementSibling : [object HTMLDivElement] after : function after() { [native code] } appendData : function appendData() { [native code] } before : function before() { [native code] } deleteData : function deleteData() { [native code] } insertData : function insertData() { [native code] } remove : function remove() { [native code] } replaceData : function replaceData() { [native code] } replaceWith : function replaceWith() { [native code] } substringData : function substringData() { [native code] } nodeType : 3 nodeName : #text baseURI : https://propansystem.net/blogsample/js/026/test2.html isConnected : true ownerDocument : [object HTMLDocument] parentNode : [object HTMLDivElement] parentElement : [object HTMLDivElement] childNodes : [object NodeList] firstChild : null lastChild : null previousSibling : [object HTMLDivElement] nextSibling : [object HTMLDivElement] nodeValue : textContent : ELEMENT_NODE : 1 ATTRIBUTE_NODE : 2 TEXT_NODE : 3 CDATA_SECTION_NODE : 4 ENTITY_REFERENCE_NODE : 5 ENTITY_NODE : 6 PROCESSING_INSTRUCTION_NODE : 7 COMMENT_NODE : 8 DOCUMENT_NODE : 9 DOCUMENT_TYPE_NODE : 10 DOCUMENT_FRAGMENT_NODE : 11 NOTATION_NODE : 12 DOCUMENT_POSITION_DISCONNECTED : 1 DOCUMENT_POSITION_PRECEDING : 2 DOCUMENT_POSITION_FOLLOWING : 4 DOCUMENT_POSITION_CONTAINS : 8 DOCUMENT_POSITION_CONTAINED_BY : 16 DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC : 32 appendChild : function appendChild() { [native code] } cloneNode : function cloneNode() { [native code] } compareDocumentPosition : function compareDocumentPosition() { [native code] } contains : function contains() { [native code] } getRootNode : function getRootNode() { [native code] } hasChildNodes : function hasChildNodes() { [native code] } insertBefore : function insertBefore() { [native code] } isDefaultNamespace : function isDefaultNamespace() { [native code] } isEqualNode : function isEqualNode() { [native code] } isSameNode : function isSameNode() { [native code] } lookupNamespaceURI : function lookupNamespaceURI() { [native code] } lookupPrefix : function lookupPrefix() { [native code] } normalize : function normalize() { [native code] } removeChild : function removeChild() { [native code] } replaceChild : function replaceChild() { [native code] } addEventListener : function addEventListener() { [native code] } dispatchEvent : function dispatchEvent() { [native code] } removeEventListener : function removeEventListener() { [native code] }
一見すると、なんらかの情報が取得できているように見えますが、注意する点として、
子要素にテキストノードが含まれているか含まれていないかが重要になります。
子要素にテキストノードが含まれている場合、子要素の取得方法を nextElementSibling を使って取得できます。
上記の例では、子要素にテキストノードが含まれているので、
nextElementSibling : [object HTMLDivElement]
という形で object HTMLDivElement が取得できていることがわかります。
では次に
<div id="c1">c1text</div>
の後の子要素の数を減らし、
HTMLは次のようにしました。
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <title>テストHTML</title> </head> <body> <div id="test1"> <div id="p1">p1text</div> <div id="p2">p2text <div id="c1">c1text</div> <div id="c2"></div> </div> <div id="p3">p3text <div id="d1">d1text</div> <div id="d2">d2text</div> <div id="d3">d3text</div> <div id="d4">d4text</div> </div> </div> <script type="text/javascript"> let c1 = document.getElementById("c1"); console.log("c1.nextSibling -> " + c1.nextSibling); // 「c1.nextSibling」の内容を確認する for(var key in c1.nextSibling){ console.log(key + " : " + c1.nextSibling[key]); } </script> </body> </html>
上記のHTMLに対して開発者ツールからconsoleを確認すると、出力結果は次のようになります。
c1.nextSibling -> [object Text] wholeText : assignedSlot : null splitText : function splitText() { [native code] } data : length : 3 previousElementSibling : [object HTMLDivElement] nextElementSibling : [object HTMLDivElement] after : function after() { [native code] } appendData : function appendData() { [native code] } before : function before() { [native code] } deleteData : function deleteData() { [native code] } insertData : function insertData() { [native code] } remove : function remove() { [native code] } replaceData : function replaceData() { [native code] } replaceWith : function replaceWith() { [native code] } substringData : function substringData() { [native code] } nodeType : 3 nodeName : #text baseURI : https://propansystem.net/blogsample/js/026/test3.html isConnected : true ownerDocument : [object HTMLDocument] parentNode : [object HTMLDivElement] parentElement : [object HTMLDivElement] childNodes : [object NodeList] firstChild : null lastChild : null previousSibling : [object HTMLDivElement] nextSibling : [object HTMLDivElement] nodeValue : textContent : ELEMENT_NODE : 1 ATTRIBUTE_NODE : 2 TEXT_NODE : 3 CDATA_SECTION_NODE : 4 ENTITY_REFERENCE_NODE : 5 ENTITY_NODE : 6 PROCESSING_INSTRUCTION_NODE : 7 COMMENT_NODE : 8 DOCUMENT_NODE : 9 DOCUMENT_TYPE_NODE : 10 DOCUMENT_FRAGMENT_NODE : 11 NOTATION_NODE : 12 DOCUMENT_POSITION_DISCONNECTED : 1 DOCUMENT_POSITION_PRECEDING : 2 DOCUMENT_POSITION_FOLLOWING : 4 DOCUMENT_POSITION_CONTAINS : 8 DOCUMENT_POSITION_CONTAINED_BY : 16 DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC : 32 appendChild : function appendChild() { [native code] } cloneNode : function cloneNode() { [native code] } compareDocumentPosition : function compareDocumentPosition() { [native code] } contains : function contains() { [native code] } getRootNode : function getRootNode() { [native code] } hasChildNodes : function hasChildNodes() { [native code] } insertBefore : function insertBefore() { [native code] } isDefaultNamespace : function isDefaultNamespace() { [native code] } isEqualNode : function isEqualNode() { [native code] } isSameNode : function isSameNode() { [native code] } lookupNamespaceURI : function lookupNamespaceURI() { [native code] } lookupPrefix : function lookupPrefix() { [native code] } normalize : function normalize() { [native code] } removeChild : function removeChild() { [native code] } replaceChild : function replaceChild() { [native code] } addEventListener : function addEventListener() { [native code] } dispatchEvent : function dispatchEvent() { [native code] } removeEventListener : function removeEventListener() { [native code] }
出力結果をよくみると、test2 の時の出力内容と変わりはありません。
DIVタグの内容を
にして取り除いたように見えますが、
「テキストノード」の解釈が違っていた為、子要素として取得ができていました。
これはテキストノードを空白として解釈していないということが言えます。
では次に、HTMLを以下のように書き換えて試してみます。
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <title>テストHTML</title> </head> <body> <div id="test1"> <div id="p1">p1text</div> <div id="p2">p2text <div id="c1">c1text</div><div id="c2">c2text</div></div> <div id="p3">p3text <div id="d1">d1text</div> <div id="d2">d2text</div> <div id="d3">d3text</div> <div id="d4">d4text</div> </div> </div> <script type="text/javascript"> let c1 = document.getElementById("c1"); console.log("c1.nextSibling -> " + c1.nextSibling); // 「c1.nextSibling」の内容を確認する for(var key in c1.nextSibling){ console.log(key + " : " + c1.nextSibling[key]); } </script> </body> </html>
上記のHTMLにアクセスしてconseleを確認すると、出力結果は次のようになりました。
c1.nextSibling -> [object HTMLDivElement] align : title : lang : translate : true dir : hidden : false accessKey : draggable : false spellcheck : true autocapitalize : contentEditable : inherit isContentEditable : false inputMode : offsetParent : [object HTMLBodyElement] offsetTop : 80 offsetLeft : 8 offsetWidth : 973 offsetHeight : 24 style : [object CSSStyleDeclaration] innerText : c2text outerText : c2text onbeforexrselect : null onabort : null onblur : null oncancel : null oncanplay : null oncanplaythrough : null onchange : null onclick : null onclose : null oncontextmenu : null oncuechange : null ondblclick : null ondrag : null ondragend : null ondragenter : null ondragleave : null ondragover : null ondragstart : null ondrop : null ondurationchange : null onemptied : null onended : null onerror : null onfocus : null onformdata : null oninput : null oninvalid : null onkeydown : null onkeypress : null onkeyup : null onload : null onloadeddata : null onloadedmetadata : null onloadstart : null onmousedown : null onmouseenter : null onmouseleave : null onmousemove : null onmouseout : null onmouseover : null onmouseup : null onmousewheel : null onpause : null onplay : null onplaying : null onprogress : null onratechange : null onreset : null onresize : null onscroll : null onseeked : null onseeking : null onselect : null onstalled : null onsubmit : null onsuspend : null ontimeupdate : null ontoggle : null onvolumechange : null onwaiting : null onwebkitanimationend : null onwebkitanimationiteration : null onwebkitanimationstart : null onwebkittransitionend : null onwheel : null onauxclick : null ongotpointercapture : null onlostpointercapture : null onpointerdown : null onpointermove : null onpointerup : null onpointercancel : null onpointerover : null onpointerout : null onpointerenter : null onpointerleave : null onselectstart : null onselectionchange : null onanimationend : null onanimationiteration : null onanimationstart : null ontransitionrun : null ontransitionstart : null ontransitionend : null ontransitioncancel : null oncopy : null oncut : null onpaste : null dataset : [object DOMStringMap] nonce : autofocus : false tabIndex : -1 attachInternals : function attachInternals() { [native code] } blur : function blur() { [native code] } click : function click() { [native code] } focus : function focus() { [native code] } enterKeyHint : onpointerrawupdate : null namespaceURI : http://www.w3.org/1999/xhtml prefix : null localName : div tagName : DIV id : c2 className : classList : slot : attributes : [object NamedNodeMap] shadowRoot : null part : assignedSlot : null innerHTML : c2text outerHTML : <div id="c2">c2text</div> scrollTop : 0 scrollLeft : 0 scrollWidth : 973 scrollHeight : 24 clientTop : 0 clientLeft : 0 clientWidth : 973 clientHeight : 24 attributeStyleMap : [object StylePropertyMap] onbeforecopy : null onbeforecut : null onbeforepaste : null onsearch : null elementTiming : onfullscreenchange : null onfullscreenerror : null onwebkitfullscreenchange : null onwebkitfullscreenerror : null children : [object HTMLCollection] firstElementChild : null lastElementChild : null childElementCount : 0 previousElementSibling : [object HTMLDivElement] nextElementSibling : null after : function after() { [native code] } animate : function animate() { [native code] } append : function append() { [native code] } attachShadow : function attachShadow() { [native code] } before : function before() { [native code] } closest : function closest() { [native code] } computedStyleMap : function computedStyleMap() { [native code] } getAttribute : function getAttribute() { [native code] } getAttributeNS : function getAttributeNS() { [native code] } getAttributeNames : function getAttributeNames() { [native code] } getAttributeNode : function getAttributeNode() { [native code] } getAttributeNodeNS : function getAttributeNodeNS() { [native code] } getBoundingClientRect : function getBoundingClientRect() { [native code] } getClientRects : function getClientRects() { [native code] } getElementsByClassName : function getElementsByClassName() { [native code] } getElementsByTagName : function getElementsByTagName() { [native code] } getElementsByTagNameNS : function getElementsByTagNameNS() { [native code] } hasAttribute : function hasAttribute() { [native code] } hasAttributeNS : function hasAttributeNS() { [native code] } hasAttributes : function hasAttributes() { [native code] } hasPointerCapture : function hasPointerCapture() { [native code] } insertAdjacentElement : function insertAdjacentElement() { [native code] } insertAdjacentHTML : function insertAdjacentHTML() { [native code] } insertAdjacentText : function insertAdjacentText() { [native code] } matches : function matches() { [native code] } prepend : function prepend() { [native code] } querySelector : function querySelector() { [native code] } querySelectorAll : function querySelectorAll() { [native code] } releasePointerCapture : function releasePointerCapture() { [native code] } remove : function remove() { [native code] } removeAttribute : function removeAttribute() { [native code] } removeAttributeNS : function removeAttributeNS() { [native code] } removeAttributeNode : function removeAttributeNode() { [native code] } replaceChildren : function replaceChildren() { [native code] } replaceWith : function replaceWith() { [native code] } requestFullscreen : function requestFullscreen() { [native code] } requestPointerLock : function requestPointerLock() { [native code] } scroll : function scroll() { [native code] } scrollBy : function scrollBy() { [native code] } scrollIntoView : function scrollIntoView() { [native code] } scrollIntoViewIfNeeded : function scrollIntoViewIfNeeded() { [native code] } scrollTo : function scrollTo() { [native code] } setAttribute : function setAttribute() { [native code] } setAttributeNS : function setAttributeNS() { [native code] } setAttributeNode : function setAttributeNode() { [native code] } setAttributeNodeNS : function setAttributeNodeNS() { [native code] } setPointerCapture : function setPointerCapture() { [native code] } toggleAttribute : function toggleAttribute() { [native code] } webkitMatchesSelector : function webkitMatchesSelector() { [native code] } webkitRequestFullScreen : function webkitRequestFullScreen() { [native code] } webkitRequestFullscreen : function webkitRequestFullscreen() { [native code] } ariaAtomic : null ariaAutoComplete : null ariaBusy : null ariaChecked : null ariaColCount : null ariaColIndex : null ariaColSpan : null ariaCurrent : null ariaDescription : null ariaDisabled : null ariaExpanded : null ariaHasPopup : null ariaHidden : null ariaKeyShortcuts : null ariaLabel : null ariaLevel : null ariaLive : null ariaModal : null ariaMultiLine : null ariaMultiSelectable : null ariaOrientation : null ariaPlaceholder : null ariaPosInSet : null ariaPressed : null ariaReadOnly : null ariaRelevant : null ariaRequired : null ariaRoleDescription : null ariaRowCount : null ariaRowIndex : null ariaRowSpan : null ariaSelected : null ariaSetSize : null ariaSort : null ariaValueMax : null ariaValueMin : null ariaValueNow : null ariaValueText : null getAnimations : function getAnimations() { [native code] } getInnerHTML : function getInnerHTML() { [native code] } nodeType : 1 nodeName : DIV baseURI : https://propansystem.net/blogsample/js/026/test4.html isConnected : true ownerDocument : [object HTMLDocument] parentNode : [object HTMLDivElement] parentElement : [object HTMLDivElement] childNodes : [object NodeList] firstChild : [object Text] lastChild : [object Text] previousSibling : [object HTMLDivElement] nextSibling : null nodeValue : null textContent : c2text ELEMENT_NODE : 1 ATTRIBUTE_NODE : 2 TEXT_NODE : 3 CDATA_SECTION_NODE : 4 ENTITY_REFERENCE_NODE : 5 ENTITY_NODE : 6 PROCESSING_INSTRUCTION_NODE : 7 COMMENT_NODE : 8 DOCUMENT_NODE : 9 DOCUMENT_TYPE_NODE : 10 DOCUMENT_FRAGMENT_NODE : 11 NOTATION_NODE : 12 DOCUMENT_POSITION_DISCONNECTED : 1 DOCUMENT_POSITION_PRECEDING : 2 DOCUMENT_POSITION_FOLLOWING : 4 DOCUMENT_POSITION_CONTAINS : 8 DOCUMENT_POSITION_CONTAINED_BY : 16 DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC : 32 appendChild : function appendChild() { [native code] } cloneNode : function cloneNode() { [native code] } compareDocumentPosition : function compareDocumentPosition() { [native code] } contains : function contains() { [native code] } getRootNode : function getRootNode() { [native code] } hasChildNodes : function hasChildNodes() { [native code] } insertBefore : function insertBefore() { [native code] } isDefaultNamespace : function isDefaultNamespace() { [native code] } isEqualNode : function isEqualNode() { [native code] } isSameNode : function isSameNode() { [native code] } lookupNamespaceURI : function lookupNamespaceURI() { [native code] } lookupPrefix : function lookupPrefix() { [native code] } normalize : function normalize() { [native code] } removeChild : function removeChild() { [native code] } replaceChild : function replaceChild() { [native code] } addEventListener : function addEventListener() { [native code] } dispatchEvent : function dispatchEvent() { [native code] } removeEventListener : function removeEventListener() { [native code] }
先ほどの test3 の時とは明らかに異なる結果になりました。
ポイントは、
<div id="c1">c1text</div><div id="c2">c2text</div></div>
c1のdivタグの直後に、空白も改行も含めず、終了divタグの直後に、c2のdivタグを書いた点です。
test3の時は
c1.nextSibling -> [object Text]
という Textオブジェクト が取得できていましたが、
test4の場合は
c1.nextSibling -> [object HTMLDivElement]
という形で、HTMLDivElementオブジェクト が取得されました。
以上のことから、nextSiblingプロパティの使い方として、空白、改行、タブ等のテキストノードを取得している場合と、
divタグそのものを取得している場合があるので、注意が必要です。
では、先ほどのHTMLを次のように変更してみます。
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <title>テストHTML</title> </head> <body> <div id="test1"> <div id="p1">p1text</div> <div id="p2">p2text<div id="c1">c1text</div></div> <div id="p3">p3text <div id="d1">d1text</div> <div id="d2">d2text</div> <div id="d3">d3text</div> <div id="d4">d4text</div> </div> </div> <script type="text/javascript"> let c1 = document.getElementById("c1"); console.log("c1.nextSibling -> " + c1.nextSibling); // 「c1.nextSibling」の内容を確認する for(var key in c1.nextSibling){ console.log(key + " : " + c1.nextSibling[key]); } </script> </body> </html>
出力結果は次のようになります。
c1.nextSibling -> null
これはdivタグの
の直後に、他の子要素(兄弟要素)が存在せず、
すぐに p2 タグの閉じたタグがある為に、このような動作になります。
以上、nextSiblingを使う場合の動きの違いを試してみました。
実際の開発時にはDOM要素を改行、空白、タブ等のテキストノードを記述することは多いので、
確実に兄弟要素を取得するには、注意した上で実装するか、
他のプロパティを使って書くとよいかと思います。