非標準のHTML属性について

Posted コメントするカテゴリー: javascript

非標準のHTML属性について

前回の投稿ではHTMLElementオブジェクトについて調べてみましたが、
HTMLElementオブジェクトは必ずしも標準のHTML属性(DOM標準)だけにあるものではなく、非標準(DOM非標準)のHTML属性も扱うことができます。

また、Element型には要素の取得として、getAttribute()メソッドが使え、
要素の設定として、setAttribute()メソッドが使えます。

例えば、とあるHTMLに対して、要素の取得や設定を行うには、次のように書きます。

HTMLドキュメントは以下のものを用意しました。

<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>テストHTML</title>
</head>
<body>

<div id="test1">
	<div id="p1" name="p1name">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" name=3>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ドキュメントに対し、getAttributeメソッドを試してみます。
getAttributeはElementのメソッド(インターフェイス)で、要素の指定した属性の値を返します。

let test1 = document.getElementById("p1").getAttribute("className");
console.log("test1 -> " + test1);

出力結果は

test1 -> p1name

になります。

ここで注意が必要な点は、値は全て文字列として取得されることです。

例えば、id=”p3″のdivタグに対して、同様にgetAttributeでname属性を取得してみます。

<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>テストHTML</title>
</head>
<body>

<div id="test1">
	<div id="p1" name="p1name">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" name=3>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 test1 = document.getElementById("p1").getAttribute("name");
console.log("test1 -> " + test1);

let test3 = document.getElementById("p3").getAttribute("name");
console.log("test3 -> " + test3);
</script>

</body>
</html>

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

出力結果は

test1 -> p1name
test3 -> 3

となりますが、後者の「3」は文字列として取得されています。

HTML属性について

Posted コメントするカテゴリー: javascript

HTML属性について

HTMLElementオブジェクトについて調べてみます。

HTMLElementオブジェクトは、HTMLの文書構造を示すHTMLタグ等の要素をもつオブジェクトと言えます。
また、各オブジェクトにはそれぞれプロパティが定義されています。
Elementオブジェクトには、次のようなオブジェクトが定義されています。(全てではありません)

id
a
link
body
title
img

上記はHTMLの文書構造を示しますが、click、blur、forcus等といったjavascriptで使われるイベントハンドラプロパティも定義されています。

各、HTMLElementオブジェクトには、要素固有の属性が定義されています。
a には href だったり、
img には src といった属性があります。

HTML属性の命名規則について

HTML属性の命名規則については、下記のようになります。

  • HTML属性のプロパティ名は小文字で記述する (但し、大文字、小文字の区別はしない)
  • javascriptのプロパティ名は大文字と小文字を区別する
  • プロパティ名が複数の単語になる場合、2語目以降の先頭は大文字として記述する
  • HTML属性の中にはjavascirptの予約語があるので、もし同一の名前を書く場合は html という文字列を先頭に追加する
  • 上記について、class については、javascriptでは予約語になるので className という形で書く
  • HTML属性のプロパティの値について

    HTML属性のプロパティの値については、文字列になりますが、
    属性が論理値を扱う場合は、プロパティの値も論理値や数値になります。

    属性の種類について

    また、属性にはHTMLの要素ごとに指定できる属性と、全ての要素に指摘できるグローバル属性、
    javascriptを実行するイベントハンドラ属性というものがあります。

    HTML5で制定されているグローバル属性は下記の13種類あります。

    acccesskey
    class
    contenteditable
    dir
    hidden
    id
    lang
    spellcheck
    style
    tabindex
    title
    translate
    data-xxxx(カスタム)
    

    最後の「カスタム」と書いたものは、 data-xxxx の「xxxx」の部分に任意の名称を下記、
    属性として利用できるものです。

    また、イベントハンドラ属性は下記のものがあります。
    それぞれの使用用途や意味については別な投稿で調べようと思います。

    onabort
    onafterprint
    onauxclick
    onbeforeprint
    onbeforeunload
    onblur
    onblur
    oncancel
    oncanplay
    oncanplaythrough
    onchange
    onclick
    onclose
    onclose
    oncontextmenu
    oncopy
    oncuechange
    oncut
    ondblclick
    ondrag
    ondragend
    ondragenter
    ondragexit
    ondragleave
    ondragover
    ondragstart
    ondrop
    ondurationchange
    onemptied
    onended
    onerror
    onfocus
    onfocus
    onhashchange
    oninput
    oninvalid
    onkeydown
    onkeypress
    onkeyup
    onlanguagechange
    onload
    onload
    onloadeddata
    onloadedmetadata
    onloadend
    onloadstart
    onmessage
    onmessageerror
    onmousedown
    onmouseenter
    onmouseleave
    onmousemove
    onmouseout
    onmouseover
    onmouseup
    onoffline
    ononline
    onpagehide
    onpageshow
    onpaste
    onpause
    onplay
    onplaying
    onpopstate
    onprogress
    onratechange
    onreset
    onresize
    onresize
    onscroll
    onscroll
    onsecuritypolicyviolation
    onseeked
    onseeking
    onselect
    onshow
    onstalled
    onstorage
    onsubmit
    onsuspend
    ontimeupdate
    ontoggle
    onunhandledrejection
    onunload
    onvolumechange
    onwaiting
    onwheel
    

    実際には上記のイベントハンドラ属性を記述してプログラムを作るより、
    javascriptのライブラリやフレームワークを使ってイベント処理を書くことが多いので、
    参考までに覚えておくという形で大丈夫と思います。

    属性について

    Posted コメントするカテゴリー: javascript

    属性について

    属性について調べてみます。

    HTMLのDOM要素には、タグ名と属性があります。
    属性は名前と値のペアで記述します。

    属性は数多く定義されており、HTMLのソース上でよく見かける属性は、alt、href、hidden、name、src、等々ありますが、
    これらは使用する用途やタグによって書き分けられます。

    属性の書き方は

    <要素名 名前="値">
    

    かんたんな例として、aタグにリンク先を表記する例がわかりやすいと思います。

    <a href="xxxxx">リンク</a>
    

    これは 「aタグ」(要素名)に対して、「href」属性をつけて、値「xxxxx」を設定しています。

    また、属性には複数の値を付与することができます。
    サンプルとしては以下のようになります。

    <要素名 名前1="値1" 名前2="値2" 名前3="値3">
    

    この場合、一つの要素に対して、3つの属性を設定していることになります。

    nodeType、nodeValue、nodeNameについて

    Posted コメントするカテゴリー: javascript

    nodeType、nodeValue、nodeNameについて

    ノードにはnodeTypeと呼ばれるノードの種類を表すものがあります。
    nodeTypeは言語仕様では12種類指定されており、現在では非推奨のものもあります。

    値はunsigned short型で定義されています。

    以下、全12種類のnodeTypeを記載します。

    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(非推奨)
    

    nodeTypeについての検証は行いませんが、前回の投稿でnextSiblingによる探索を試した際、
    HTMLのDOMからTextオブジェクトを取得した結果をconsole出力した結果を記載していました。
    具体的には2つの例になりますが、その時の出力結果を引用すると、

    「Textオブジェクト」の場合、nodeType は 3 が取得できていました。
    (以下の出力はnextSiblingを試した時のもの)

    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
    (以下省略)
    

    また、「HTMLDivElementオブジェクト」の場合、nodeType は 1 が取得できていました。
    (以下の出力はnextSiblingを試した時のもの)

    c1.nextSibling -> [object HTMLDivElement]
    align : 
    title : 
    lang : 
    translate : true
    dir : 
    hidden : false
    accessKey : 
    draggable : false
    spellcheck : true
    autocapitalize : 
    (出力途中は省略)
    nodeType : 1
    nodeName : DIV
    

    また、nodeValueについては、Textオブジェクトに持つ内容を示し、
    nodeNameについては、そのオブジェクトが持つElementのタグ名を示します。

    nextSibling による探索

    Posted コメントするカテゴリー: 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要素を改行、空白、タブ等のテキストノードを記述することは多いので、
    確実に兄弟要素を取得するには、注意した上で実装するか、
    他のプロパティを使って書くとよいかと思います。

    firstChild、lastChildによる探索

    Posted コメントするカテゴリー: javascript

    firstChild、lastChildによる探索

    親要素からみて子要素をfirstChildとlastChildで取得する方法を試してみます。
    まずは、前回投稿したHTMLを少し改造して、下記の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 id="c4">c4text</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>
    </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 id="c4">c4text</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 p2 = document.getElementById("p2");
    	console.log("p2.firstChild -> " + p2.firstChild);
    </script>
    
    </body>
    </html>
    

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

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

    p2.firstChild -> [object Text]
    

    親要素のp2に対して、オブジェクトの「Text」が取得できていることがわかります。
    次に、この p2.firstChild の内容を詳しく出力してみます。
    愚直な方法ですが、for 取得できたp2.firstChildの内容を全てみてみます。

    先ほどの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 id="c4">c4text</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 p2 = document.getElementById("p2");
    	console.log("p2.firstChild -> " + p2.firstChild);
    
    	// 「p2.firstChild」の内容を確認する
    	for(var key in p2.firstChild){
    		console.log(key + " : " + p2.firstChild[key]);
    	}
    </script>
    
    </body>
    </html>
    

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

    ログには次のように表示されました。

    p2.firstChild -> [object Text]
    wholeText : p2text
    		
    assignedSlot : null
    splitText : function splitText() { [native code] }
    data : p2text
    		
    length : 9
    previousElementSibling : null
    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/025/test3.html
    isConnected : true
    ownerDocument : [object HTMLDocument]
    parentNode : [object HTMLDivElement]
    parentElement : [object HTMLDivElement]
    childNodes : [object NodeList]
    firstChild : null
    lastChild : null
    previousSibling : null
    nextSibling : [object HTMLDivElement]
    nodeValue : p2text
    		
    textContent : p2text
    		
    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] }
    

    p2.firstChildの要素にアクセスし、テキストオブジェクトの内容が列挙されて出力されました。
    出力内容の中の「data」プロパティをみると、「data : p2text」と表示されていることから、

    	<div id="p2">p2text
    		<div id="c1">c1text</div>
    		<div id="c2">c2text</div>
    		<div id="c3">c3text</div>
    		<div id="c4">c4text</div>
    	</div>
    

    上記の部分の 「

    p2text 」の要素が取得されていることがわかります。
    id 「p2」に対しての一番最初の要素としてp2textという文字列(テキストオブジェクトのdata)が出力されています。

    では次に「lastChild」の場合はどうなるか、試してみます。
    1つ前の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 id="c4">c4text</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 p2 = document.getElementById("p2");
    	console.log("p2.lastChild -> " + p2.lastChild);
    
    	// 「p2.lastChild」の内容を確認する
    	for(var key in p2.lastChild){
    		console.log(key + " : " + p2.lastChild[key]);
    	}
    </script>
    
    </body>
    </html>
    

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

    ログには次のように表示されました。

    p2.lastChild -> [object Text]
    wholeText : 
    	
    assignedSlot : null
    splitText : function splitText() { [native code] }
    data : 
    	
    length : 2
    previousElementSibling : [object HTMLDivElement]
    nextElementSibling : null
    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/025/test4.html
    isConnected : true
    ownerDocument : [object HTMLDocument]
    parentNode : [object HTMLDivElement]
    parentElement : [object HTMLDivElement]
    childNodes : [object NodeList]
    firstChild : null
    lastChild : null
    previousSibling : [object HTMLDivElement]
    nextSibling : null
    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] }
    

    p2.firstChildの取得の時と同様に、要素内の値を「data」のプロパティで取得できるかと思いましたが、
    p2.lastChildの場合は、実際には何も取得はされず、空白(厳密にいうとソース内のタブ文字列)が出力されています。

    では、p2.lastChildはどこの何を取得しようとしているのか、もう少し詳しく調べてみます。

    先ほどのHTMLを変更して、次のHTMLを設置しました。

    の要素の最後に「p2text2」という文字列を記述してみました。

    <!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 id="c4">c4text</div>
    		p2text2
    	</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 p2 = document.getElementById("p2");
    	console.log("p2.lastChild -> " + p2.lastChild);
    
    	// 「p2.lastChild」の内容を確認する
    	for(var key in p2.lastChild){
    		console.log(key + " : " + p2.lastChild[key]);
    	}
    </script>
    
    </body>
    </html>
    

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

    今度は、出力結果は次のようになります。

    p2.lastChild -> [object Text]
    wholeText : 
    		p2text2
    	
    assignedSlot : null
    splitText : function splitText() { [native code] }
    data : 
    		p2text2
    	
    length : 12
    previousElementSibling : [object HTMLDivElement]
    nextElementSibling : null
    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/025/test5.html
    isConnected : true
    ownerDocument : [object HTMLDocument]
    parentNode : [object HTMLDivElement]
    parentElement : [object HTMLDivElement]
    childNodes : [object NodeList]
    firstChild : null
    lastChild : null
    previousSibling : [object HTMLDivElement]
    nextSibling : null
    nodeValue : 
    		p2text2
    	
    textContent : 
    		p2text2
    	
    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] }
    

    p2.lastChild のdataプロパティにある「p2text2」という文字列が出力されていることがわかります。

    ただし、上記の例の場合、半ば強引に値を取得するようにHTMLを記述したので、
    実際には厳密な仕様を把握していません。

    仕様上は、p2のノードのうち、最後の子ノードを取得するのがlastChildで、子ノードがない場合はnullを取得する。という仕様になります。

    このあたりは実際のコーディングやHTML側のDOMの状態に応じて注意して実装する必要がありそうです。

    childNodesによる探索

    Posted コメントするカテゴリー: javascript

    childNodesによる探索

    親要素からみて子要素(childNodes)を取得する方法を試してみます。

    まずは、下記の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 id="c4">c4text</div>
    	</div>
    	<div id="p3">p3text</div>
    </div>
    
    </body>
    </html>
    

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

    このHTMLに対して、idがp2のdivタグを親として、子要素をchildNodesを使って取得してみます。

    まずは、下記のように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 id="c4">c4text</div>
    	</div>
    	<div id="p3">p3text</div>
    </div>
    
    <script type="text/javascript">
    	let p2 = document.getElementById("p2");
    	console.log("p2.childNodes -> " + p2.childNodes);
    </script>
    
    </body>
    </html>
    

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

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

    p2.childNodes -> [object NodeList]
    

    親要素のp2に対して、NodeListが取得できていることがわかります。

    次に、この p2.childNodes の内容を詳しく出力してみます。
    先ほどの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 id="c4">c4text</div>
    	</div>
    	<div id="p3">p3text</div>
    </div>
    
    <script type="text/javascript">
    	let p2 = document.getElementById("p2");
    	console.log("p2.childNodes -> " + p2.childNodes);
    	console.log("p2.childNodes -> " + p2.childNodes[0]);
    </script>
    
    </body>
    </html>
    

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

    ログには次のように表示されました。

    p2.childNodes -> [object NodeList]
    p2.childNodes -> [object Text]
    

    p2.childNodesの1つ目の要素にアクセスし、そのオブジェクトの内容が [object Text] であることがわかりました。

    それでは、さらに追記して下記のように変更しました。

    <!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 id="c4">c4text</div>
    	</div>
    	<div id="p3">p3text</div>
    </div>
    
    <script type="text/javascript">
    	let p2 = document.getElementById("p2");
    
    	// divタグ「p2」の childNodes を出力
    	console.log("p2.childNodes -> " + p2.childNodes);
    
    	// childNodesを配列とみたてて各要素にアクセスする
    	console.log("p2.childNodes 0 -> " + p2.childNodes[0]);
    	console.log("p2.childNodes 1 -> " + p2.childNodes[0]['data']);
    
    	// 「p2.childNodes」の内容を確認する
    	for(var key in p2.childNodes[0]){
    		console.log(key + " : " + p2.childNodes[0][key]);
    	}
    </script>
    
    </body>
    </html>
    

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

    ログには次のように表示されました。

    2.childNodes -> [object NodeList]
    p2.childNodes 0 -> [object Text]
    p2.childNodes 1 -> p2text
    
    wholeText : p2text
    
    assignedSlot : null
    splitText : function splitText() { [native code] }
    data : p2text
    
    length : 5
    previousElementSibling : null
    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/024/test4.html
    isConnected : true
    ownerDocument : [object HTMLDocument]
    parentNode : [object HTMLDivElement]
    parentElement : [object HTMLDivElement]
    childNodes : [object NodeList]
    firstChild : null
    lastChild : null
    previousSibling : null
    nextSibling : [object HTMLDivElement]
    nodeValue : p2text
    		
    textContent : p2text
    		
    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() { 
    

    p2.childNodes 1 -> p2text と表示されている行から、 p2.childNodes[0][‘data’] を出力すると、

    タグのテキスト情報「p2text」を取得していることがわかります。

    では次に、div id=”c1″ の内容を取得してみます。

    先ほどのHTMLを変更して、次の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 id="c4">c4text</div>
    	</div>
    	<div id="p3">p3text</div>
    </div>
    
    <script type="text/javascript">
    	let p2 = document.getElementById("p2");
    
    	// divタグ「p2」の childNodes を出力
    	console.log("p2.childNodes -> " + p2.childNodes);
    
    	// childNodesを配列とみたてて各要素にアクセスする
    	console.log("p2.childNodes 0 -> " + p2.childNodes[0]);
    	console.log("p2.childNodes 0 -> " + p2.childNodes[0]['data']);
    
    	console.log("p2.childNodes 1 -> " + p2.childNodes[1]);
    	console.log("p2.childNodes 1 -> " + p2.childNodes[1].innerHTML);
    </script>
    
    </body>
    </html>
    

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

    出力結果は次のようになります。

    p2.childNodes -> [object NodeList]
    p2.childNodes 0 -> [object Text]
    p2.childNodes 0 -> p2text
    
    p2.childNodes 1 -> [object HTMLDivElement]
    p2.childNodes 1 -> c1text
    

    p2.childNodes[1] という形で、配列の1つ目にアクセスすると、

    タグにアクセスしていることがわかります。
    さらに、p2.childNodes[1].innerHTML で要素内のHTMLを取得してみると「c1text」というHTML内の値を取得できていることがわかります。

    同様に、他の要素にもアクセスしてみます。
    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 id="c4">c4text</div>
    	</div>
    	<div id="p3">p3text</div>
    </div>
    
    <script type="text/javascript">
    	let p2 = document.getElementById("p2");
    
    	// divタグ「p2」の childNodes を出力
    	console.log("p2.childNodes -> " + p2.childNodes);
    
    	// childNodesを配列とみたてて各要素にアクセスする
    	console.log("p2.childNodes 0 -> " + p2.childNodes[0]);
    	console.log("p2.childNodes 0 -> " + p2.childNodes[0]['data']);
    
    	console.log("p2.childNodes 1 -> " + p2.childNodes[1]);
    	console.log("p2.childNodes 1 -> " + p2.childNodes[1].innerHTML);
    	console.log("p2.childNodes 2 -> " + p2.childNodes[2]);
    	console.log("p2.childNodes 2 -> " + p2.childNodes[2].innerHTML);
    	console.log("p2.childNodes 3 -> " + p2.childNodes[3]);
    	console.log("p2.childNodes 3 -> " + p2.childNodes[3].innerHTML);
    	console.log("p2.childNodes 4 -> " + p2.childNodes[4]);
    	console.log("p2.childNodes 4 -> " + p2.childNodes[4].innerHTML);
    	console.log("p2.childNodes 5 -> " + p2.childNodes[5]);
    	console.log("p2.childNodes 5 -> " + p2.childNodes[5].innerHTML);
    	console.log("p2.childNodes 6 -> " + p2.childNodes[6]);
    	console.log("p2.childNodes 6 -> " + p2.childNodes[6].innerHTML);
    	console.log("p2.childNodes 7 -> " + p2.childNodes[7]);
    	console.log("p2.childNodes 7 -> " + p2.childNodes[7].innerHTML);
    	console.log("p2.childNodes 8 -> " + p2.childNodes[8]);
    	console.log("p2.childNodes 8 -> " + p2.childNodes[8].innerHTML);
    </script>
    
    </body>
    </html>
    

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

    出力結果は次のようになります。

    p2.childNodes -> [object NodeList]
    p2.childNodes 0 -> [object Text]
    p2.childNodes 0 -> p2text
    
    p2.childNodes 1 -> [object HTMLDivElement]
    p2.childNodes 1 -> c1text
    p2.childNodes 2 -> [object Text]
    p2.childNodes 2 -> undefined
    p2.childNodes 3 -> [object HTMLDivElement]
    p2.childNodes 3 -> c2text
    p2.childNodes 4 -> [object Text]
    p2.childNodes 4 -> undefined
    p2.childNodes 5 -> [object HTMLDivElement]
    p2.childNodes 5 -> c3text
    p2.childNodes 6 -> [object Text]
    p2.childNodes 6 -> undefined
    p2.childNodes 7 -> [object HTMLDivElement]
    p2.childNodes 7 -> c4text
    p2.childNodes 8 -> [object Text]
    p2.childNodes 8 -> undefined
    

    ここでわかることは、p2の要素としてchildNodesを取得した結果として、
    p2.childNodes[1].innerHTML の値は、要素c1タグの「c1text」が取得できていますが、
    p2.childNodes[2].innerHTML の値は未定義(undefined)になることです。

    p2.childNodes[3].innerHTML の値を取得して初めて、画面上の次の値である「c2text」が取得できました。
    同様に、c4textの値も、childNodesの7つ目の要素「p2.childNodes[7].innerHTML」で初めて取得できています。

    p2の要素としてchildNodesを取得する際、一見すると配列の値として順番に画面上の値が取得できそうですが、
    厳密にDOM要素の順番に要素を取得していることがわかります。

    また、「p2.childNodes[1]」の中にどんな情報が格納されているかを確かめてみます。
    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 id="c4">c4text</div>
    	</div>
    	<div id="p3">p3text</div>
    </div>
    
    <script type="text/javascript">
    	let p2 = document.getElementById("p2");
    
    	// divタグ「p2」の childNodes を出力
    	console.log("p2.childNodes -> " + p2.childNodes);
    
    	// childNodesを配列とみたてて各要素にアクセスする
    	console.log("p2.childNodes 0 -> " + p2.childNodes[0]);
    	console.log("p2.childNodes 0 -> " + p2.childNodes[0]['data']);
    
    	console.log("p2.childNodes 1 -> " + p2.childNodes[1]);
    	console.log("p2.childNodes 1 -> " + p2.childNodes[1].innerHTML);
    
    	// 「p2.childNodes[1]」の内容を確認する
    	for(var key in p2.childNodes[1]){
    		console.log(key + " : " + p2.childNodes[1][key]);
    	}
    </script>
    
    </body>
    </html>
    

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

    出力結果は次のようになります。

    p2.childNodes -> [object NodeList]
    p2.childNodes 0 -> [object Text]
    p2.childNodes 0 -> p2text
    
    p2.childNodes 1 -> [object HTMLDivElement]
    p2.childNodes 1 -> c1text
    align : 
    title : 
    lang : 
    translate : true
    dir : 
    hidden : false
    accessKey : 
    draggable : false
    spellcheck : true
    autocapitalize : 
    contentEditable : inherit
    isContentEditable : false
    inputMode : 
    offsetParent : [object HTMLBodyElement]
    offsetTop : 56
    offsetLeft : 8
    offsetWidth : 997
    offsetHeight : 24
    style : [object CSSStyleDeclaration]
    innerText : c1text
    outerText : c1text
    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] }
    onpointerrawupdate : null
    enterKeyHint : 
    namespaceURI : http://www.w3.org/1999/xhtml
    prefix : null
    localName : div
    tagName : DIV
    id : c1
    className : 
    classList : 
    slot : 
    attributes : [object NamedNodeMap]
    shadowRoot : null
    part : 
    assignedSlot : null
    innerHTML : c1text
    outerHTML : <div id="c1">c1text</div>
    scrollTop : 0
    scrollLeft : 0
    scrollWidth : 997
    scrollHeight : 24
    clientTop : 0
    clientLeft : 0
    clientWidth : 997
    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 : null
    nextElementSibling : [object HTMLDivElement]
    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
    getInnerHTML : function getInnerHTML() { [native code] }
    getAnimations : function getAnimations() { [native code] }
    nodeType : 1
    nodeName : DIV
    baseURI : https://propansystem.net/blogsample/js/024/test7.html
    isConnected : true
    ownerDocument : [object HTMLDocument]
    parentNode : [object HTMLDivElement]
    parentElement : [object HTMLDivElement]
    childNodes : [object NodeList]
    firstChild : [object Text]
    lastChild : [object Text]
    previousSibling : [object Text]
    nextSibling : [object Text]
    nodeValue : null
    textContent : c1text
    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] }
    

    keyの名前の出力部分を見てわかるとおり、[object HTMLDivElement]の一連の要素名が格納されていることがわかります。

    実際のプログラムの実装ではchildNodes内の各要素を正確に把握して、取得した要素内の[object HTMLDivElement]の値を必要に応じて取得して実装を行います。

    要素の探索

    Posted コメントするカテゴリー: javascript

    要素の探索

    ドキュメント内の要素(Element)はツリー構造になっています。
    このツリー構造の要素を探索する方法を試してみます。

    実際に下記のHTMLファイルを作成し、サーバに設置してみました。
    サンプル画面

    <!DOCTYPE html>
    <html lang="ja">
    <head>
    <meta charset="UTF-8">
    <title>テストHTML</title>
    </head>
    <body>
    
    <div id="test1">
    	<div id="test1_1">
    		a
    	</div>
    	<div id="test1_2">
    		b
    
    		<div id="test1_2_1">
    			b1
    		</div>
    		<div id="test1_2_2">
    			b2
    		</div>
    
    		<div id="test2_2_1">
    			id_b1
    		</div>
    		<div id="test2_2_2">
    			id_b2
    		</div>
    
    	</div>
    	<div id="test1_3">
    		b
    	</div>
    </div>
    
    <script type="text/javascript">
    
    	let test1_2_1 = document.getElementById("test1_2_1");
    
    	// オブジェクトの内容を確認する
    	for(var key in test1_2_1){
    		console.log(key + " : " + test1_2_1[key]);
    	}
    
    	console.log("test1_2_1 -> " + test1_2_1);
    	console.log("test1_2_1.parentNode -> " + test1_2_1.parentNode);
    	console.log("test1_2_1.parentElement -> " + test1_2_1.parentElement);
    
    
    </script>
    
    </body>
    </html>
    

    上記のHTMLソースには「id=”test1″」のdivタグ内にネストされた形で

    「id=”test1_1″」
    「id=”test1_2″」
    「id=”test1_3″」

    のdivタグがそれぞれあります。

    この状態でツリー構造の要素を取得する方法を試してみます。
    具体的には以下の要素取得のコードを書いてみます。

    parentNodeによる探索

    要素の「test1_2_1」に対して、「parentNode」を使って親要素を取得してみます。
    以下のように取得のtest1_2_1を取得し、取得した要素に.parentNodeを使って親要素を取得してみます。

    	let test1_2_1 = document.getElementById("test1_2_1");
    	console.log("test1_2_1.parentNode -> " + test1_2_1.parentNode);
    

    結果は、次のように出力されます。

    test1_2_1 -> [object HTMLDivElement]
    test1_2_1.parentNode -> [object HTMLDivElement]
    test1_2_1.parentElement -> [object HTMLDivElement]
    

    .parentNodeと取得しても、.parentElementと取得しても、出力内容に違いはないように見えますが、
    厳密には異なる取得方法になるので、使い分けが必要です。

    .parentNodeはidが「test1_2_1」の親ノードの「test1_2」のNodeを示します。

    また、.parentElement については、Nodeを親に持つインターフェースで、XMLで使用されます。

    HTML(DOM)のcssセレクタによる要素の選択

    Posted コメントするカテゴリー: javascript

    HTML(DOM)のcssセレクタによる要素の選択

    HTMLソース内にあるcssセレクタによる要素の選択を試してみます。
    以下のソースがある場合、HTML本文内にあるdivタグの選択をします。

    <!DOCTYPE html>
    <html lang="ja">
    <head>
    <meta charset="UTF-8">
    <title>テストHTML</title>
    
    </head>
    <body>
     
    <div class="test">test1</div>
    <div class="test">test2</div>
    <div class="test">test3</div>
    <div class="test">test4</div>
    <div class="test">test5</div>
    
    <div id="testid">testid</div>
    
    
    <script type="text/javascript">
    
    let test_class1 = document.querySelector('.test');
    console.log("test_class1 -> " + test_class1);
    
    let test_class2 = document.querySelectorAll('test');
    console.log("test_class2 -> " + test_class2);
    
    </script>
    
    </body>
    </html>
    

    コンソールの出力は以下のようになります。

    
    test_class1 -> [object HTMLDivElement]
    
    test_class2 -> [object NodeList]
    
    

    要素の取得方法としては「querySelector」を使う場合と、「querySelectorAll」を使う場合があります。

    前者は画面内のドキュメント全体から、最初に見つかった要素を1つだけ取得し、
    後者は画面内のドキュメント全体から、該当する要素を全て取得していることがわかります。

    また、後者は [object NodeList] という出力なので、NodeListが返されていることもわかります。

    HTML(DOM)のclassによる要素の選択

    Posted コメントするカテゴリー: javascript

    HTML(DOM)のclassによる要素の選択

    HTMLソース内にあるclass名による要素の選択を試してみます。
    以下のソースがある場合、HTML本文内にあるdivタグの選択をします。

    <!DOCTYPE html>
    <html lang="ja">
    <head>
    <meta charset="UTF-8">
    <title>テストHTML</title>
    
    </head>
    <body>
     
    <div class="test">test1</div>
    <div class="test">test2</div>
    <div class="test">test3</div>
    <div class="test">test4</div>
    <div class="test">test5</div>
    
    <script type="text/javascript">
    let test_class = document.getElementsByClassName('test');
    console.log("test_class -> " + test_class);
    </script>
    
    </body>
    </html>
    

    コンソールの出力は以下のようになります。

    test_class -> [object HTMLCollection]
    

    続いて、javascriptを下記のように書き変えて、test_classで取得できた内容を出力してみます。

    
    <script type="text/javascript">
    let test_class = document.getElementsByClassName('test');
    
    console.log("test_class -> " + test_class);
    
    Array.prototype.forEach.call(test_class, function(item) {
        console.dir(item);
    });
    
    </script>
    
    

    結果は、次のようになります。

    test_class -> [object HTMLCollection]
    test.html:21 div.test
    test.html:21 div.test
    test.html:21 div.test
    test.html:21 div.test
    test.html:21 div.test
    

    という出力になりました。

    ただし、これはブラウザの開発ツールで見た結果なので、
    「div.test」の中にはさらに詳細な情報が含まれています。

    例えば、一番上の「div.test」を展開してみると、次のような結果になります。

    div.test
    accessKey: ""
    align: ""
    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
    assignedSlot: null
    attributeStyleMap: StylePropertyMap {size: 0}
    attributes: NamedNodeMap {0: class, class: class, length: 1}
    autocapitalize: ""
    autofocus: false
    baseURI: "https://propansystem.net/blogsample/js/021/test.html"
    childElementCount: 0
    childNodes: NodeList [text]
    children: HTMLCollection []
    classList: DOMTokenList ["test", value: "test"]
    className: "test"
    clientHeight: 24
    clientLeft: 0
    clientTop: 0
    clientWidth: 1007
    contentEditable: "inherit"
    dataset: DOMStringMap {}
    dir: ""
    draggable: false
    elementTiming: ""
    enterKeyHint: ""
    firstChild: text
    firstElementChild: null
    hidden: false
    id: ""
    innerHTML: "test1"
    innerText: "test1"
    inputMode: ""
    isConnected: true
    isContentEditable: false
    lang: ""
    lastChild: text
    lastElementChild: null
    localName: "div"
    namespaceURI: "http://www.w3.org/1999/xhtml"
    nextElementSibling: div.test
    nextSibling: text
    nodeName: "DIV"
    nodeType: 1
    nodeValue: null
    nonce: ""
    offsetHeight: 24
    offsetLeft: 8
    offsetParent: body
    offsetTop: 8
    offsetWidth: 1007
    onabort: null
    onanimationend: null
    onanimationiteration: null
    onanimationstart: null
    onauxclick: null
    onbeforecopy: null
    onbeforecut: null
    onbeforepaste: null
    onbeforexrselect: null
    onblur: null
    oncancel: null
    oncanplay: null
    oncanplaythrough: null
    onchange: null
    onclick: null
    onclose: null
    oncontextmenu: null
    oncopy: null
    oncuechange: null
    oncut: 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
    onfullscreenchange: null
    onfullscreenerror: null
    ongotpointercapture: null
    oninput: null
    oninvalid: null
    onkeydown: null
    onkeypress: null
    onkeyup: null
    onload: null
    onloadeddata: null
    onloadedmetadata: null
    onloadstart: null
    onlostpointercapture: null
    onmousedown: null
    onmouseenter: null
    onmouseleave: null
    onmousemove: null
    onmouseout: null
    onmouseover: null
    onmouseup: null
    onmousewheel: null
    onpaste: null
    onpause: null
    onplay: null
    onplaying: null
    onpointercancel: null
    onpointerdown: null
    onpointerenter: null
    onpointerleave: null
    onpointermove: null
    onpointerout: null
    onpointerover: null
    onpointerrawupdate: null
    onpointerup: null
    onprogress: null
    onratechange: null
    onreset: null
    onresize: null
    onscroll: null
    onsearch: null
    onseeked: null
    onseeking: null
    onselect: null
    onselectionchange: null
    onselectstart: null
    onstalled: null
    onsubmit: null
    onsuspend: null
    ontimeupdate: null
    ontoggle: null
    ontransitioncancel: null
    ontransitionend: null
    ontransitionrun: null
    ontransitionstart: null
    onvolumechange: null
    onwaiting: null
    onwebkitanimationend: null
    onwebkitanimationiteration: null
    onwebkitanimationstart: null
    onwebkitfullscreenchange: null
    onwebkitfullscreenerror: null
    onwebkittransitionend: null
    onwheel: null
    outerHTML: "<div class=\"test\">test1</div>"
    outerText: "test1"
    ownerDocument: document
    parentElement: head
    parentNode: head
    part: DOMTokenList [value: ""]
    prefix: null
    previousElementSibling: title
    previousSibling: text
    scrollHeight: 24
    scrollLeft: 0
    scrollTop: 0
    scrollWidth: 1007
    shadowRoot: null
    slot: ""
    spellcheck: true
    style: CSSStyleDeclaration {additiveSymbols: "", alignContent: "", alignItems: "", alignSelf: "", alignmentBaseline: "", …}
    tabIndex: -1
    tagName: "DIV"
    textContent: "test1"
    title: ""
    translate: true
    __proto__: HTMLDivElement
    

    これも、前回の名前で取得した時と同様、divタグをjavascript側のオブジェクトとして取得していることがわかります。

    また、メソッドもプロパティも同様に含まれているので、プログラミングをしてdivタグを操作することが可能になります。

    HTML(DOM)のタグ名(型)による要素の選択

    Posted コメントするカテゴリー: javascript

    HTML(DOM)のタグ名(型)による要素の選択

    HTMLソース内にあるタグ名による要素の選択を試してみます。
    以下のソースがある場合、HTML本文内にあるdivタグの選択をします。

    HTMLソース内にdivタグの組み合わせが一つしかない場合は、それ単一で、
    複数ある場合は、NodeListオブジェクトを取得します。

    HTMLタグは大文字でも小文字でも取得されます。(区別されない)

    実際に下記のHTMLソースをサーバ上に置き、ブラウザからアクセスして試してみます。

    <!DOCTYPE html>
    <html lang="ja">
    <head>
    <meta charset="UTF-8">
    <title>テストHTML</title>
    
    </head>
    <body>
     
    <div>test1</div>
    <div>test2</div>
    <div>test3</div>
    <div>test4</div>
    <div>test5</div>
    
    <script type="text/javascript">
    let test_tag = document.getElementsByTagName('div');
    console.log("test_tag -> " + test_tag);
    </script>
    
    </body>
    </html>
    

    コンソールの出力は以下のようになります。

    test_tag -> [object HTMLCollection]
    

    先ほどNodeListオブジェクトと書きましたが、開発ツールで確認すると、
    HTMLCollections という値になりました。

    では、このHTMLCollectionsに対して、javascriptからアクセスしてみます。

    先ほどのHTMLソース内のjavascriptの箇所に、下記のように追記してみます。

    
    <script type="text/javascript">
    let test_tag = document.getElementsByTagName('div');
    console.log("test_tag -> " + test_tag);
    
    Array.prototype.forEach.call(test_tag, function(item) {
        console.dir(item);
    });
    
    </script>
    
    

    結果は、次のようになります。
    (ここでは便宜上console.dirを使って確認しています)

    test_tag -> [object HTMLCollection]
    test.html:21 
    div
    accessKey: ""
    align: ""
    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
    assignedSlot: null
    attributeStyleMap: StylePropertyMap {size: 0}
    attributes: NamedNodeMap {length: 0}
    autocapitalize: ""
    autofocus: false
    baseURI: "https://propansystem.net/blogsample/js/020/test.html"
    childElementCount: 0
    childNodes: NodeList [text]
    children: HTMLCollection []
    classList: DOMTokenList [value: ""]
    className: ""
    clientHeight: 24
    clientLeft: 0
    clientTop: 0
    clientWidth: 1006
    contentEditable: "inherit"
    dataset: DOMStringMap {}
    dir: ""
    draggable: false
    elementTiming: ""
    enterKeyHint: ""
    firstChild: text
    firstElementChild: null
    hidden: false
    id: ""
    innerHTML: "test1"
    innerText: "test1"
    inputMode: ""
    isConnected: true
    isContentEditable: false
    lang: ""
    lastChild: text
    lastElementChild: null
    localName: "div"
    namespaceURI: "http://www.w3.org/1999/xhtml"
    nextElementSibling: div
    nextSibling: text
    nodeName: "DIV"
    nodeType: 1
    nodeValue: null
    nonce: ""
    offsetHeight: 24
    offsetLeft: 8
    offsetParent: body
    offsetTop: 8
    offsetWidth: 1006
    onabort: null
    onanimationend: null
    onanimationiteration: null
    onanimationstart: null
    onauxclick: null
    onbeforecopy: null
    onbeforecut: null
    onbeforepaste: null
    onbeforexrselect: null
    onblur: null
    oncancel: null
    oncanplay: null
    oncanplaythrough: null
    onchange: null
    onclick: null
    onclose: null
    oncontextmenu: null
    oncopy: null
    oncuechange: null
    oncut: 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
    onfullscreenchange: null
    onfullscreenerror: null
    ongotpointercapture: null
    oninput: null
    oninvalid: null
    onkeydown: null
    onkeypress: null
    onkeyup: null
    onload: null
    onloadeddata: null
    onloadedmetadata: null
    onloadstart: null
    onlostpointercapture: null
    onmousedown: null
    onmouseenter: null
    onmouseleave: null
    onmousemove: null
    onmouseout: null
    onmouseover: null
    onmouseup: null
    onmousewheel: null
    onpaste: null
    onpause: null
    onplay: null
    onplaying: null
    onpointercancel: null
    onpointerdown: null
    onpointerenter: null
    onpointerleave: null
    onpointermove: null
    onpointerout: null
    onpointerover: null
    onpointerrawupdate: null
    onpointerup: null
    onprogress: null
    onratechange: null
    onreset: null
    onresize: null
    onscroll: null
    onsearch: null
    onseeked: null
    onseeking: null
    onselect: null
    onselectionchange: null
    onselectstart: null
    onstalled: null
    onsubmit: null
    onsuspend: null
    ontimeupdate: null
    ontoggle: null
    ontransitioncancel: null
    ontransitionend: null
    ontransitionrun: null
    ontransitionstart: null
    onvolumechange: null
    onwaiting: null
    onwebkitanimationend: null
    onwebkitanimationiteration: null
    onwebkitanimationstart: null
    onwebkitfullscreenchange: null
    onwebkitfullscreenerror: null
    onwebkittransitionend: null
    onwheel: null
    outerHTML: "<div>test1</div>"
    outerText: "test1"
    ownerDocument: document
    parentElement: head
    parentNode: head
    part: DOMTokenList [value: ""]
    prefix: null
    previousElementSibling: title
    previousSibling: text
    scrollHeight: 24
    scrollLeft: 0
    scrollTop: 0
    scrollWidth: 1006
    shadowRoot: null
    slot: ""
    spellcheck: true
    style: CSSStyleDeclaration {additiveSymbols: "", alignContent: "", alignItems: "", alignSelf: "", alignmentBaseline: "", …}
    tabIndex: -1
    tagName: "DIV"
    textContent: "test1"
    title: ""
    translate: true
    __proto__: HTMLDivElement
    

    という出力になりました。
    これはHTMLCollections内の要素にアクセスしたところ、HTMLDivElementというオブジェクトが返されたことになります。

    HTML(DOM)の名前による要素の選択

    Posted コメントするカテゴリー: javascript

    HTML(DOM)の名前による要素の選択

    前回の投稿ではDOMのid要素により、javascriptから要素を取得する方法を試しましたが、
    name属性でも同様に要素を取得できるので試してみます。

    例えば、HTMLソースが以下の場合の要素「test_youso2」を取得してみます。

    <!DOCTYPE html>
    <html lang="ja">
    <head>
    <meta charset="UTF-8">
    <title>テストHTML</title>
    
    </head>
    <body>
     
    <h3>タイトル</h3>
    <p name="test_dom2">テスト要素2</p>
    
    <script type="text/javascript">
    let test_dom2 = document.getElementsByName('test_dom2');
    console.log("test_dom2 -> " + test_dom2);
    </script>
    
    </body>
    </html>
    

    また、HTMLソース内のname属性は、そのソース内で一意である必要はなく、重複して構成されていても問題はありません。

    上記HTMLにブラウザでアクセスすると、javascriptが実行され、コンソールログにはNodeListオブジェクトが出力されます。
    NodeListオブジェクトは一見すると配列のように見えますが、配列オブジェクトとは異なります。Arrayオブジェクトではないとも言えます。
    NodeListオブジェクトでは、itemメソッドとlengthプロパティが使えます。

    itemメソッドはNodeListオブジェクトのインデックスとして作用し、lengthプロパティは、取得できたオブジェクトの個数を返します。

    要素の選択

    Posted コメントするカテゴリー: javascript

    要素の選択

    javascriptからHTML内のドキュメント要素を操作する方法を整理します。
    要素を操作するには、要素を取得してから操作をします。

    この取得する方法はプレーンなjavascriptでは次の方法があります。

    ①id属性で選択
    ②name属性で選択
    ③tag名で選択
    ④cssクラスで選択
    ⑤cssセレクタで選択

    またjavascriptで作られたライブラリ(jquery等)や、react、vue、Angular、その他のjavascriptで作られているフレームワークは、それぞれで書き方が変わってきます。

    ここでは上記の①~⑤について、試してみます。

    id属性で取得

    HTML内のソースがHTMLElement要素として書かれていて、
    タグ内にid属性を持つ場合、javascriptでは次のように要素を取得できます。

    例えば、HTMLソースが以下の場合の要素「test_youso1」を取得してみます。

    <!DOCTYPE html>
    <html lang="ja">
    <head>
    <meta charset="UTF-8">
    <title>テストHTML</title>
    
    </head>
    <body>
     
    <h3>タイトル</h3>
    <p id="test_dom1">テスト要素1</p>
    
    <script type="text/javascript">
    let test_dom1 = document.getElementById('test_dom1');
    console.log("test_dom1 -> " + test_dom1);
    
    //取得した要素の文字色を青く設定
    test_dom1.style.color = 'blue';
    </script>
    
    </body>
    </html>
    

    javascriptでは、次のように要素を取得します。

    let test_dom1 = document.getElementById('test_dom1');
    console.log("test_dom1 -> " + test_dom1);
    
    //取得した要素の文字色を青く設定
    test_dom1.style.color = 'blue';
    

    また、HTMLソース内のid要素は、そのソース内で一意であることが前提になります。

    上記のHTMLを保存し、ブラウザでアクセスすると、
    「タイトル」と「テスト要素1」 (青文字に変更された文字列)が表示されます。

    ノードについて

    Posted コメントするカテゴリー: javascript

    ノードについて

    前回の投稿でDocument内の各要素をノードで表記しました。

    このノードはjavascriptの言語仕様で言うNodeオブジェクトになります。

    Nodeオブジェクトということは、プロパティやメソッドを持つので、
    プロパティとメソッドがそれぞれどのようになっているのか、調べてみます。

    前回投稿した下記のHTMLを元にノードを考えてみます。

    <!DOCTYPE html>
    <html lang="ja">
    <head>
    <meta charset="UTF-8">
    <title>propansystem開発ブログ</title>
    </head>
    <body>
     
    <h1>ブログタイトル</h1>
    <p>ブログ本文内の<b>太字</b>テキストです</p>
     
    </body>
    </html>
    

    まずドキュメント全体を指し示すのがDocumentノードといい、HTML要素はElementノード、テキストを表すものはTextノードです。

    Document、Element、Textノードは、Nodeオブジェクトの派生ノードで、DocumentとElementはDOM操作において重要なDOMクラスと言えます。

    また、Nodeオブジェクトの派生型については、大きく分けてDocument型とElement型に分かれ、
    Element型は、HTMLElementオブジェクトとして画面上のHTMLタグ(ドキュメント)を表します。
    Document型は、ブラウザに読み込まれたウェブページを表します(DOMツリーのエントリポイントを表します)

    HTMLElement型について

    HTMLElementには多数の派生型があり、一般的にはHTMLタグの要素を示します。
    派生型ごとにjavascriptのプロパティが定義され、指定した要素と同じ値が格納されます。

    ノードの種類については、上で書いた
    Document、DocumentFragment、Element、の他にCaracterData(Text、Comment)、Attr等があります。

    各ノードは「属性」を持ち、子ノードは親ノードの属性を継承して参照することができます。
    Elementノードは名前/値のペアで扱えるメソッドが定義されています。

    DOMについて

    Posted コメントするカテゴリー: javascript

    DOMについて

    DOM(Document Object Model)について、掘りげて調べてみます。

    DOMはHTML、XMLのドキュメント内部のコンテンツを表現するものと言えます。

    ブラウザに表示される画面のHTML構造を見てみると、ツリー構造になっていて、
    それぞれがタグで書かれています。

    タグについては、開始タグと終了タグで内容を囲み(一部開始/終了の意味を持たない単一のタグもあります)、
    そのタグ内に内容を意味するテキストを記載します。

    また、タグの中には要素を表すノード、テキスト文字を表すノードが含まれます。

    このブログを表現しているHTMLタグを抜粋し、コンテンツ(内容)部分を全て簡易的に書いたものが下記のタグになります。

    <!DOCTYPE html>
    <html lang="ja">
    <head>
    <meta charset="UTF-8">
    <title>propansystem開発ブログ</title>
    </head>
    <body>
    
    <h1>ブログタイトル</h1>
    <p>ブログ本文内の<b>太字</b>テキストです</p>
    
    </body>
    </html>
    

    このHTMLの例でも、ツリー構造ととらえることが可能です。

    ツリー構造は、一番上をDocumentとして、その下にhtml、そのさらに下にhead、bodyがあり、
    bodyの下にh1、pタグがある。
    という構造をしています。

    また、それぞれのタグにはノードと呼ぶつながりがあります。
    さらに、タグには上下関係があり、一つ上のツリー(のタグ)を親ノードと呼びます。
    そのノートの直下にあるタグは子ノードと呼ばれます。

    あるノードより下にあるノードのさらに下にあるノードは子孫ノードと呼びます。
    あるノードより上にあるノードのさらに上にあるノードは祖先ノードと呼びます。

    ノードについては、さらにnodeオブジェクトとしての考え方があるので、
    nodeオブジェクトとプロパティ、メソッドについて、さらに深く調べてみます。

    javascriptからDOMを操作する

    Posted コメントするカテゴリー: javascript

    javascriptからDOMを操作する

    これまではjavascriptを言語仕様の目線から調べたものを書いてきました。

    ここからはjavascriptから画面に表示されたHTMLを変更したり、更新したりする方法を試します。

    一言で画面に表示されたHTMLといっても、javascriptがどう捉えているのか、わかったうえでプログラムを書かないと制御が難しくなります。

    すべてのHTMLファイルはWindowオブジェクトを持ち、Windowオブジェクトの中にdocumentプロパティがあります。
    documentプロパティはDocumentオブジェクトを参照し、このDocumentオブジェクトが画面内のコンテンツを表しています。

    この時、画面内のコンテンツを表すものが、DOMと呼ばれるものです。
    (DOMはDocument Object Modelの略です)

    フレーム間の変数の値の受け渡しについて

    Posted コメントするカテゴリー: javascript

    フレーム間の変数の値の受け渡しについて

    フレーム間の変数の値の受け渡しについて

    前回の投稿では、フレームを利用した場合の、親フレームと子フレームの関係で動きを試しました。

    今回は、一つのフレームに子フレームが複数ある場合、
    その子フレーム間での変数の値がどのように取得できるのかを試してみます。

    前回の投稿と同じ、以下のようなHTMLを用意します。
    (便宜上jquery.jsを読み込んでいますが、必須ではありません)

    まず、各フレームをまとめるtest.htmlを一つ

    <html>
    <head>
    <title>フレーム使用例</title>
    <script src="./jquery.js"></script>
    <script src="./main.js"></script>
    </head>
    
    <frameset rows="150,*">
        <frame id="frm1" name="frm1" src="test1.html">
        <frameset cols="250,*">
            <frame id="frm2" name="frm2" src="test2.html">
            <frame id="frm3" name="frm3" src="test3.html">
        </frameset>
        <noframes>
            このページはフレームを使用しています。
        </noframes>
    </frameset>
    
    </html> 
    

    それと、

    各フレームのhtmlファイル

    test1.html
    test2.html
    test3.html
    

    test1.html、test2.html、test3.html
    はそれぞれ親フレームから呼ばれる子画面のHTMLです。

    それぞれのhtmlファイルは以下のように書きました。わかりやすいように内容はほぼ同一で、画面表示時にアラート出力をしています。(最終的な検証では削除します)

    test1.html

    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="UTF-8">
        <title>test window1</title>
        <script src="./jquery.js"></script>
    </head>
    <body>
    
    <script type="text/javascript">
    alert("クライアントサイドjs 1");
    var test1 = "aaa";
    alert(window.test1);
    </script>
    
    test 1
    
    </body>
    </html>
    

    test2.html

    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="UTF-8">
        <title>test window2</title>
        <script src="./jquery.js"></script>
    </head>
    <body>
    
    <script type="text/javascript">
    alert("クライアントサイドjs 2");
    
    //ここでtest1.html内の変数にアクセスしている
    alert(parent.frm1.test1);
    
    </script>
    
    test 2
    
    </body>
    </html>
    

    test3.html

    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="UTF-8">
        <title>test window3</title>
        <script src="./jquery.js"></script>
    </head>
    <body>
    
    <script type="text/javascript">
    alert("クライアントサイドjs 3");
    </script>
    
    test 3
    
    </body>
    </html>
    

    ここまでのファイルを準備して、各ファイルにjavascriptを埋め込んで動作を確かめてみます。

    まず、test1.htmlのjavascript内に、以下のように変数を代入します。

    let test1 = "aaa";
    

    次に、このtest1.htmlで代入した変数を、test2.html内で読み込んでアラート表示してみます。

    test2.html

    alert(parent.frm1.test1);
    

    ここまでで、ブラウザからtest.htmlにアクセスすると、
    ダイアログがtest1.htmlの読み込みで2回、test2.htmlの読み込みで2回、test3.htmlの読み込みで1回、表示されます。

    ポイントとなる点は、test1.htmlで格納した変数に、test2.htmlからアクセスしている点です。
    test2.htmlから

    parent.frm1.test1
    

    という書き方をして、フレームごしのtest1.htmlに代入した変数にアクセスしています。

    ところが、最近のjavascriptの変数の宣言はletで書くことが主流といえるので、
    試しにletで書いてみたところ、test2.htmlのダイアログ出力ではundefinedが表示されました。
    これはletで宣言した変数にフレーム間で呼び出すことができないスコープが存在していることと言えます。

    実際にサーバ上に設置したhtmlは以下のURLで確認できます。
    https://propansystem.net/blogsample/js/015/

    フレームをまたぐ関数の受け渡しについて

    次に、フレーム間で変数を受け渡すのではなく、関数を宣言して受け渡してみます。

    先ほどと同様に、test1.html、test2.html、test3.htmlを用意し、
    test1.html内に関数を宣言します。

    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="UTF-8">
        <title>test window1</title>
        <script src="./jquery.js"></script>
    </head>
    <body>
    
    <script type="text/javascript">
    
    function test1func() {
    	alert("test1func");
    }
    
    </script>
    
    test 1
    
    </body>
    </html>
    

    次に、test2.htmlで、test1.htmlで定義した関数を呼び出します。

    test2.html

    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="UTF-8">
        <title>test window2</title>
        <script src="./jquery.js"></script>
    </head>
    <body>
    
    <script type="text/javascript">
    alert("test2 start !");
    parent.frm1.test1func();
    </script>
    
    
    test 2
    
    </body>
    </html>
    

    こうすることで、test2.htmlからフレームごしのtest1.htmlに書かれた関数「test1func」を呼ぶことができます。

    この時に注意する点としては、
    ・関数をフレームごしに呼ぶ場合は、スコープに注意する。
    ・関数内でグローバル変数を参照すると、「関数を書いた側」のフレームのプロパティが検索される。
    ・ユーザ定義関数とは別に、javascriptがもともと定義されている関数を呼び出す場合は、コンストラクタとコンストラクタのプロトタイプオブジェクトは、フレームごとに別々に持っている。

    という点になります。
    ただ、ここは詳しく実装して検証してみないとイメージしずらいので、
    別な投稿としてとりあげたいと思います。

    フレームオブジェクトについて

    Posted コメントするカテゴリー: javascript

    フレームについて

    ウィンドウをオープンした時にwindowオブジェクトをjavascriptから参照したように、
    同じドキュメント内にあるframeに対しても、親画面から子画面(子frame)に対して参照ができます。

    例えば、以下のようなHTMLを用意します。

    test1.html
    test2.html
    test3.html
    

    はそれぞれ、親画面から呼び出される子画面(フレーム)です。
    親画面から上記の3ファイルを呼び出すHTMLを用意します。

    <html>
    <head>
    <title>フレーム使用例</title>
    <script src="./jquery.js"></script>
    <script src="./main.js"></script>
    </head>
    
    <frameset rows="150,*">
        <frame id="frm1" src="test1.html" name="ue">
        <frameset cols="250,*">
            <frame id="frm2" src="test2.html" name="hidari">
            <frame id="frm3" src="test3.html" name="migi">
        </frameset>
        <noframes>
            このページはフレームを使用しています。
        </noframes>
    </frameset>
    
    </html> 
    

    画面表示は、このようになります。

    このHTMLに対して、main.js内で以下のようにframeオブジェクトを参照してみます。

    $(function(){
    
    	//フレームを取得(オブジェクトとして取得される)
    	let frm1 = $('#frm1');
    	console.log("frm1 -> " + frm1);
    
    	//フレームのwindowオブジェクトを参照する方法
    	let frm1_cw = frm1[0].contentWindow;
    	console.log("frm1_cw -> " + frm1_cw);
    	
    	//windowオブジェクトに標準に定義されている「frames」プロパティを参照する
    	console.log("frames -> " + frames[0]);
    
    });
    

    ブラウザにアクセスした結果、コンソール画面には次のように出力されます。

    frm1 -> [object Object]
    frm1_cw -> [object Window]
    frames -> [object Window]
    

    出力結果から、「$(‘#frm1’)」で参照した場合と、「frm1[0].contentWindow」と「frames[0]」で参照したものはオブジェクトの種類が異なります。

    id指定で取得したものはObjectになり、残りの2つで参照したものはwindow(オブジェクト)になります。

    フレーム内のdocumentに対して、操作をしてみます。

    先ほどのjavascriptに以下のように追記します。

    	window.onload = function(){
    		frames[1].document.body.style.background = "#99CCFF";
    	}
    

    ここでは、2つめのフレームに対して、bodyタグの背景色を変更しています。
    window.onloadを使わない場合、親ウィンドウの全てのコンテンツが読み込まれないままjavascriptの処理が終わるので、背景色をjavascriptで変更した後、子ウィンドウがロードされて処理が無効になってしまいます。

    実行した画面は次のようになります。

    実際に設置した動作例は、以下のURLです。
    https://propansystem.net/blogsample/js/014/

    ウィンドウクローズ

    Posted コメントするカテゴリー: javascript

    ウィンドウのクローズ

    前回の投稿ではウィンドウをオープンを試しました。
    今回は開いたウィンドウを閉じてみます。

    まずは親ウィンドウとなるHTMLを用意します。
    jqueryと、main.jsを読み込んでいます。

    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="UTF-8">
        <title>test</title>
        <script src="./jquery.js"></script>
        <script src="./main.js"></script>
    </head>
    <body>
    
    親ウィンドウ
    
    </body>
    </html>
    

    次に、main.jsの中身です。

    $(function(){
    
        //新規ウィンドウを開く
        let w = window.open("test.html", "test", "width=400,height=500");
    
    });
    

    スクリプトがロードされたら問答無用で新しいウィンドウ(test.html)を開いています。

    test.htmlの中身は次のように書いておきます。

    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="UTF-8">
        <title>test window</title>
        <script src="./jquery.js"></script>
        <script src="./sub.js"></script>
    </head>
    <body>
    
    test window
    
    <div id="cwindow">ウィンドウを閉じる</div>
    
    </body>
    </html>
    

    最後にsub.jsを用意します。

    $(function(){
    	$("#cwindow").click(function(){
    		window.close();
    	});
    });
    

    これも、シンプルに「

    ウィンドウを閉じる

    」のdivタグがクリックされた時にウィンドウを閉じる命令を書いています。

    ここまでの一連のファイルで、親ウィンドウから子ウィンドウを開いて、子ウィンドウのリンクをクリックすると、子ウィンドウが閉じる。
    という動きになります。

    ウィンドウのクローズ時の注意点

    ここで、注意が必要なのは、子ウィンドウを閉じる時の命令です。
    上記の例では、windowオブジェクトを直接使っていますが、
    親ウィンドウで生成した

    let w = window.open("test.html", "test", "width=400,height=500");
    

    の「w」を使って、

    w.close();
    

    という命令もありますが、この例ではそれは動作しません。

    動作しない理由としては、親ウィンドウで定義した「w」に子ウィンドウからアクセスできない為に子ウィンドウを閉じることができません。

    ウィンドウオープン

    Posted コメントするカテゴリー: javascript

    ウィンドウオープン

    javascriptを使って、開いているウィンドウ(ブラウザ)からさらに別なウィンドウを開く方法があります。

    通常、ブラウザで開いている画面とは別に、別なブラウザで別画面を開いている場合は、その2つのウィンドウ間ではjavascriptのプログラムからは直接アクセスできません。

    ただ、今回試すウィンドウオープンの方法で開いたウィンドウは、javascriptを使ってDOM要素にアクセスしたり、値の受け渡しが可能になります。

    最も簡単なウィンドウを開く命令を書いてみます。

    //新規ウィンドウを開く
    let w = window.open("test.html", "test", "width=400,height=500");
    

    実行すると、ブラウザにアクセスした際にjavascriptが起動されると、新規ウィンドウが開きます。

    //ウィンドウオブジェクトを生成し、アラートを開く
    let w = window.open();
    w.alert("test");
    
    //ウィンドウオブジェクトを生成し、新規ウィンドウを開き、指定URLへ遷移する
    let w2 = window.open();
    w2.location = "https://google.com";
    

    上記の記述方法は、一見すると最初に書いたサンプルと同じ動きになりますが、
    openerプロパティを使うことで、開いたウィンドウのオブジェクトを取得できる点が大きく違います。
    具体的な動きを試しに書いてみます。

    //ウィンドウオブジェクトを生成し、新規ウィンドウを開き、指定URLへ遷移する
    let w3 = window.open();
    console.log(w3.open().opener);
    
    
    let w4 = window.open();
    w4.location = "https://google.com";
    console.log(w4.open().opener);
    

    w3の場合と、w4の場合は、console.logの出力結果が違い、どちらもオープンしたウィンドウの情報が取得できるのですが、
    locationの値を代入したw4の場合は、取得結果がw3とは異なる結果になっていることがわかります。

    下記のキャプチャ画像は、それぞれのログ出力結果です。

    w3のログ出力

    w4のログ出力

    windowsオブジェクトとID

    Posted コメントするカテゴリー: javascript

    windowsオブジェクトとID

    windowドキュメント内でのID属性の使い方について、まとめます。

    javascriptライブラリのjqueryでの開発が主流だった時には、ひとつの画面内の(ドキュメント内の)DOM要素に対してID属性を指定して、要素にアクセスするという方法が多くありました。
    もちろんjqueryを使わない、javascriptのみでID属性を使ってDOMにアクセスする方法もあり、その場合に注意する点をまとめてみます。

    ・DOMに対し、ID属性を付与する場合、windowオブジェクトに同じ名前のプロパティが存在する場合、処理が意図しないものになる
    ・上記の場合、同一のID属性を定義したDOM要素がある場合は、ドキュメント内のDOM要素が定義される。(例えば、inputや)
    ・IDの名称がHTMLのタグ名と同じものは指定できない(指定したとしてもjs上で一意ではないので誤動作の原因になる)

    ダイアログボックス

    Posted コメントするカテゴリー: javascript

    ダイアログボックス

    ダイアログボックスを試してみます。
    ダイアログボックスは画面表示時に、ユーザの操作に関係なく、メッセージを「表示/確認/入力」する為のダイアログを表示します。

    具体的には、alert、confirm、propmtがあり、それぞれブラウザの表示またはロード中の状態を停止した上で、画面描画系の操作を受け付けない形で表示されます。

    主に、alertはプレーンテキストによるメッセージ、confirmはOK/キャンセルの確認ボタン、promptはユーザの入力待ちのダイアログボックス、をそれぞれ表示します。
    下記にシンプルな例を書いて試してみます。

    alert('入力お願いします');
    
    do {
        name = prompt("お名前を入力してください");
        conf = confirm(name + 'でよろしいですか?');
    } while (!conf || (name == '' || name == 'null'));
    
    alert('入力ありがとう' + name + 'さん');
    

    ブラウザで実行すると、まず最初に「入力をお願いします」というメッセージダイアログが表示されます。
    ダイアログ上の「OKボタン」を押すと次に、「お名前を入力してください」というメッセージとともに、テキスト入力欄があるダイアログボックスが表示されます。
    その次に「(入力したお名前)でよろしいですか?」という確認ダイアログが表示されます。
    確認ダイアログでOKボタンを押した場合は、最後に「入力ありがとう(入力したお名前)さん」のメッセージが表示されます。

    サンプルなので、実用性はほぼ無く入力チェック等は甘いですが、必要最小限の動作の確認はできました。

    最もシンプルなダイアログボックスの表示方法ですが、最近のjavascript界隈の動きでは、reactやvue、その他ライブラリを使ったダイアログボックス、ダイアログウィンドウ、モーダルウィンドウ、等の表示方法、利用方法が多数あります。
    利用シーンは開発環境、開発体制等に応じて実装方法を合わせていくようにすると良いかと思います。

    Screenオブジェクト

    Posted コメントするカテゴリー: javascript

    Screenオブジェクト

    Screenオブジェクトを試してみます。
    ScreenオブジェクトはWindowオブジェクトの画面に関係する情報を提供します。

    下記にサンプルコードを書いてみます。

    let scr1 = screen.availWidth;
    console.log('scr1 -> ' + scr1);
    
    let scr2 = screen.availHeight;
    console.log('scr2 -> ' + scr2);
    
    let scr3 = screen.colorDepth;
    console.log('scr3 -> ' + scr3);
    
    let scr4 = screen.pixelDepth;
    console.log('scr4 -> ' + scr4);
    

    上記を実行すると、下記のような結果になります。

    scr1 -> 1920
    scr2 -> 1170
    scr3 -> 24
    scr4 -> 24
    

    検証に使用したPCでは、有効画面幅1920px、有効画面高さ1170px、画面の色深度24、仮想画面の色深度24という値が出力されました。
    この値は実行するPCやブラウザにより影響を受けるので、それぞれのマシンでの値が出力されます。

    また、有効画面の幅と高さではなく、物理的なモニターの幅と高さを求めるには、次の出力命令を使います。

    let scr5 = screen.width;
    console.log('scr5 -> ' + scr5);
    
    let scr6 = screen.height;
    console.log('scr6 -> ' + scr6);
    

    出力結果は

    scr5 -> 1920
    scr6 -> 1200
    

    となり、実際のモニターのサイズ(WUXGA)の値が出力されます。(出力結果は実行するPC環境によって大きく異なります)

    Navigatorオブジェクト

    Posted コメントするカテゴリー: javascript

    Navigatorオブジェクト

    Navigatorオブジェクトを試してみます。
    Navigatorオブジェクトはブラウザ関係の情報が格納されています。

    下記にサンプルコードを書いてみます。

    let navi1 = navigator.userAgent;
    console.log('navi1 -> ' + navi1);
    
    let navi2 = navigator.appName;
    console.log('navi2 -> ' + navi2);
    
    let navi3 = navigator.appVersion;
    console.log('navi3 -> ' + navi3);
    
    let navi4 = navigator.platform;
    console.log('navi4 -> ' + navi4);
    
    let navi5 = navigator.oscpu;
    console.log('navi5 -> ' + navi5);
    
    

    上記を実行すると、下記のような結果になります。

    navi1 -> Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:80.0) Gecko/20100101 Firefox/80.0
    navi2 -> Netscape
    navi3 -> 5.0 (Windows)
    navi4 -> Win32
    navi5 -> Windows NT 10.0; Win64; x64
    

    検証に使用したブラウザはFirefoxで、同じコードをChromeで確認すると、次のようになります。

    navi1 -> Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.135 Safari/537.36
    navi2 -> Netscape
    navi3 -> 5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.135 Safari/537.36
    navi4 -> Win32
    navi5 -> undefined
    

    ただ、値の4つめ「navi4」のplatformについては、検証に使っているOSが64bit版windows10ですが、なぜかWin32という出力になります。
    これはブラウザ間の出力を統一する為に、先にChromeが「Win32」という出力をする作りにした為、その後にFirefoxがChromeの出力に合わせ、ブラウザが返すOS情報を統一して出力するようになったという歴史的背景があるようです。
    こちらのサイト「Firefox サイト互換性情報」にその辺りの説明が詳しく記述されています。

    また、5つめの「navi5」についてはChromeでは定義されておらず、undefinedになります。
    この辺りもブラウザ間で微妙に差異がある為、プログラム実装時には注意が必要と言えます。

    locationオブジェクト

    Posted コメントするカテゴリー: javascript

    locationオブジェクト

    locationオブジェクトを試してみます。
    locationオブジェクトはウィンドウに表示されているURLを表したり、その他ウィンドウのURLに関連する操作を行えます。
    このオブジェクトに対して、メソッドやプロパティを試してみます。

    簡単にURL関連のlocationオブジェクトを表示してみます。

    console.log(window.location.href);
    console.log(location.href);
    console.log(Location.href);
    

    上の例では、わざと間違った記述をしてみました。
    結果は、

    https://javascriptを実行したドメイン名/
    https://javascriptを実行したドメイン名/
    undefined
    

    という結果になりました。
    3つめの命令では、locationの先頭の文字が大文字の為、オブジェクトとして解釈できなかった為、undefinedになりました。

    また、1つめと2つめの違いは、「window.」を記述するかしないか。という違いでしたが、
    これはlocationオブジェクト自体windowオブジェクトなので、省略しても2つめの記述が問題なく動作することがわかります。

    それでは、別な例を試してみます。

    console.log(location.host);
    console.log(location.hostname);
    console.log(location.protocol);
    console.log(location.port);
    console.log(location.pathname);
    console.log(location.search);
    console.log(location.hash);
    

    それぞれ実行した結果は

    propansystem.net
    propansystem.net
    https: main.js
    <empty string> main.js
    /実行したjavascriptまでのパス/ main.js
    <empty string> main.js
    <empty string>
    

    という結果になりました。

    ここでは詳しい言語仕様は割愛しますが、上記のサンプルを動作した際のURLに対し、
    もしURLの末尾にパラメータが「index.php?aaa=1&bbb=2&ccc=3」のように付与されている場合は、
    location.searchの結果が

    ?aaa=1&bbb=2&ccc=3
    

    という出力になります。
    javascriptでは、URLのパラメータを利用してはいけないというルールはないので、
    開発プログラムによっては、サーバサイドプログラムのGETの値と同様の実装の仕方ができると言えます。
    (例えばPHP言語だと「$_GET」パラメータのように)

    windowオブジェクト

    Posted コメントするカテゴリー: javascript

    Windowオブジェクト

    windowオブジェクトについて、簡単なサンプルを書きつつ、挙動をみてみます。

    タイマー

    以前の投稿で、windowオブジェクトの指定時間経過後のプログラム実行のサンプルを書きました。

    その動きもタイマーの機能と言えますが、指定時間経過後ではなく、
    指定時間ごとの一定の間隔でプログラムを実行するという命令もあります。
    簡単に下記のサンプルを書いて動かしてみます。

    let i = 0;
    setInterval("output_log(i++)", 3000);
    
    function output_log(i) {
        console.log('hello -> ' + i);
    }
    

    setIntervalを使ったシンプルな例です。
    第一引数については、主にメソッドを指定しますが、ダブルクォートで囲わないと動作しませんでした。

    同一出身ポリシー(同一オリジンポリシー)について

    Posted コメントするカテゴリー: javascript

    同一出身ポリシー(同一オリジンポリシー)について

    javascriptで読み込まれたプログラムが、1つのサーバ(ドメイン)から読み込まれた場合、
    特に問題なく動作しますが、2つのサーバA、Bがあり、サーバAにアクセスした際に、サーバBのjavascriptを読み込む実装方法も実現できます。

    この時に同一出身ポリシーの考え方と挙動が適用されるので理解と注意が必要です。

    同一出身ポリシーについて簡単にまとめます。

    ・①サーバAから読み込まれたjavascriptはサーバBのドキュメントにアクセスすることはできない。
    ・②同じポリシーのウィンドウや、ドキュメントにはアクセスができる。
    ・③プロトコル(httpやhttps)が異なる形でドキュメントがロードされた場合、別な出身ポリシーとなる。
    ・④javascriptのプログラムファイルは、別サーバからロードしても、動作に問題はでない。
    (サーバAにあるjavascriptプログラムを、サーバBで読み込んだ場合、サーバBにあるドキュメントにアクセスができる)
    ・⑤AJAX等の通信時にも同一出身ポリシーが適用され、サーバAからAJAX通信をした場合、サーバBにアクセスすることはできない。(注…javascriptライブラリの実装方法で別サーバ間での通信を行う技術的解決方法はある)
    ・⑥サブドメインを利用したサーバ間通信では、別なサーバとみなされる。(javascriptのDocumentオブジェクトの設定方法により、同一出身ポリシーとみなし、それぞれ別なサブドメインにアクセルする方法はある)

    細かい部分では実際に開発を進めていく上で挙動を確認しながら把握することがよいと思います。

    ④については、AJAX通信を利用し、jsonp形式のコールバック関数経由で別サーバへの通信を行うことができます。
    上記はjqueryライブラリを利用することで実装ができます。

    また、最近ではjqueryライブラリ以外のjavascriptフレームワークが主流になってきているので、それぞれのフレームワークのドキュメントをもとに開発するケースが多いです。

    javascriptの制限

    Posted コメントするカテゴリー: javascript

    javascriptの制限

    javascriptをwebブラウザで動作させる場合、各ブラウザにより差がありますが、機能が制限されています。
    機能の制限については、ブラウザごとに差があるので、プログラムの開発中に都度確認する必要があります。

    主な制限については、ブラウザごとの差異はなく、一般的に下記の点があります。

    ・クライアント側のファイルにアクセスすること
    ・クライアント側の任意のディレクトリにアクセスすること
    ・汎用的なネットワークプログラムができないこと(APIの利用やHTTPプロトコル通信を利用する方法はアリ)
    ・javascriptから開いた新規ブラウザウィンドウの制御に対しての制限
    ・ファイルアップロード処理のイベント処理(勝手にクライアントマシンのファイルをアップロードすることができないように)
    ・他サーバからロードされたjavascriptプログラムを、クライアントマシンのjavascript側でロードし実行すること

    また各種ブラウザごとの制限については、ここでは網羅できませんが、
    システムの開発中に機能ごとに調べて実装を進める必要があります。

    クライアントサイドのjavascriptの実行順について

    Posted コメントするカテゴリー: javascript

    クライアントサイドのjavascriptの実行順について

    javascriptがブラウザ上で実行される実行順についてまとめます。

    全てのブラウザ、全ての場合に下記のような実行順が保証される訳ではなく、
    ブラウザがHTMLやjavascript、その他、ブラウザ上に読み込まれるコンテンツをローディング、解釈、表示(出力)などを行う場合の参考の実行順として考えることができます。

    また、HTMLパーサもブラウザごとのバージョンにより挙動が細かく変わるので、一概に実行環境を固定して考えることは、現実的ではないと考えられます。

    さらにjavascriptのフレームワーク固有の挙動の違いもあるので、それぞれの実行順はプログラムを書いて確かめてみることがベストと思います。

    • 1.ブラウザの起動と同時に、Documentオブジェクトが作られる。
      HTML要素、テキスト、の解釈
      ドキュメントに対してElement、Textを追加。
    • 2.インラインスクリプト(HTMLタグ内に記述したjavascript)や、外部javascriptスクリプト(の読み込み指定がある場合)を実行する。
      この時の実行は同期実行される。
    • 3.HTMLパーサはasync属性が設定された<script>要素を解釈するときは、スクリプトのダウンロードを開始、ドキュメントの解釈も開始、
      このとき、HTMLパーサはダウンロードや、解釈を待たない。
    • 4.defer属性が設定されたスクリプトがドキュメント中に記述された順で実行される。
      非同期で実行されるスクリプトもある。
    • 5.ドキュメントが解釈できたら、Documentオブジェクトに対して、DOMContentLoadedイベントが発生。
      プログラム実行は非同期イベントドリブンの状態になる。
    • 6.ブラウザが全て読み込み完了した後、Windwosオブジェクトに対してloadイベントを発生させる。
      この時、サイズの大きい画像や、その他のファイルが引き続きローディング中になる場合もある。
    • 7.上記までの処理が完了した後、ユーザの入力や操作によるイベント、時間経過等によるイベントハンドラが非同期で呼び出される。

    HTML内でのjavascriptコードの記述

    Posted コメントするカテゴリー: javascript

    HTML内でのjavascriptコードの記述

    javascriptをHTML文書内で使用する方法についてまとめます。

    HTML内にjavascriptを書く方法は、次の書き方があります。

    1.scriptタグ内に記述する

    2.外部ファイル化したjavascriptを読み込む

    3.HTMLタグにイベントハンドラとして記述する

    次に、それぞれ具体的にどのように書くのかを確かめつつ、書いてみます。

    1.scriptタグ内に記述する

    headタグもしくはbodyタグ内にscriptタグを書いてその中に記述する方法です。
    次のようなHTMLファイルを作成し、ブラウザからアクセスしてみます。

    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="UTF-8">
    <title>test</title>
    
    <script>
    alert('test');
    </script>
    
    </head>
    <body>
    
    </body>
    </html>
    

    アクセスした結果、

    <script></script>

    タグ内に記述したjavascriptが動作し、アラートが表示されます。

    2.外部ファイル化したjavascriptを読み込む

    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="UTF-8">
    <title>test</title>
    
    <script src="./main.js"></script>
    
    </head>
    <body>
    
    </body>
    </html>
    

    外部ファイルのjavascriptには、上記同様に次のように書きます。
    ファイル名はmain.jsとして作成し、HTMLファイルと同じ場所に置きます。

    alert('test2');
    

    HTMLファイルにアクセスすると、ダイアログが表示されます。

    src属性を書いた場合は、

    <script></script>

    タグ内に記述したjavascriptは無効になります。

    外部ファイル化した場合、javascriptのプログラムファイルがブラウザにキャッシュされるので注意が必要です。(注:ブラウザ標準の動作として)

    src属性には外部サーバのjavascriptを読み込むことも可能です。

    3.HTMLタグ内にインラインでjavascriptを記述する

    HTMLタグ属性にjavascriptのプログラムを直接記述することができます。

    下記の簡単なサンプルを書いて、ブラウザでアクセスしてみます。

    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="UTF-8">
    <title>test</title>
    
    </head>
    <body>
    
    <div class="test_div" onClick="alert('test3');">testABC</div>
    
    </body>
    </html>
    

    上記のサンプルでは、ブラウザにアクセスした段階では、特になにも起きません。

    画面上に「testABC」という文字列が表示されるので、その文字列をクリックしたタイミングでアラートが表示されます。

    この場合の、onClickはイベントハンドラと呼ばれており、クリックした場合の処理を走らせることができます。
    この他にもイベントハンドラには種類があるので、目的に合わせてプログラムを実装します。

    また、alertメソッドのみでサンプルを書きましたが、実際にはここに外部ファイル等に定義したユーザ関数を割り当て、
    その関数内でロジックを実装していく形が多いです。

    実際のプロダクト開発では、HTMLに直接記述する場面は多くはなく、外部ファイル化したjavascriptを利用する、
    または最近ではjavascriptのフレームワークが多数あるので、その機構に沿ってロジックを組み立てる場合が多いです。

    例としては、React、Vue、Next、Angular等々…。多数のフレームワークが存在します。
    このブログでもjavascriptの基本的な部分を抑えた後、各種フレームワークに触れていきます。