nextSibling による探索

javascript

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はこちら(test1)

この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>

サーバ上のHTMLはこちら(test2)

この結果、開発ツールのログには、以下のように出力されます。

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はこちら(test3)

上記の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はこちら(test4)

上記の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タグの

c1text

の直後に、他の子要素(兄弟要素)が存在せず、
すぐに p2 タグの閉じたタグがある為に、このような動作になります。

以上、nextSiblingを使う場合の動きの違いを試してみました。

実際の開発時にはDOM要素を改行、空白、タブ等のテキストノードを記述することは多いので、
確実に兄弟要素を取得するには、注意した上で実装するか、
他のプロパティを使って書くとよいかと思います。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です