Linux Professional Institute Learning Logo.
main contentにスキップ
  • ホーム
    • 全てのリソース
    • LPI学習教材
    • コントリビューターになる
    • Publishing Partners
    • Publishing Partnerになる
    • About
    • FAQ
    • コントリビューター
    • Roadmap
    • 連絡先
  • LPI.org
034.4 レッスン 1
課題 031: ソフトウェア開発とWebテクノロジー
031.1 ソフトウェア開発の基本
  • 031.1 レッスン 1
031.2 Webアプリケーションのアーキテクチャ
  • 031.2 レッスン 1
031.3 HTTP の基礎
  • 031.3 レッスン 1
課題 032: HTMLドキュメントマークアップ
032.1 HTMLドキュメントの構造
  • 032.1 レッスン 1
032.2 HTMLのセマンティックスとドキュメント階層
  • 032.2 レッスン 1
032.3 HTMLにおける参照と埋め込みリソース
  • 032.3 レッスン 1
032.4 HTMLフォーム
  • 032.4 レッスン 1
課題 033: CSSコンテンツ スタイリング
033.1 CSSの基本
  • 033.1 レッスン 1
033.2 CSSセレクターとスタイルアプリケーション
  • 033.2 レッスン 1
033.3 CSSスタイリング
  • 033.3 レッスン 1
033.4 CSSボックスモデルとレイアウト
  • 033.4 レッスン 1
課題 034: JavaScriptプログラミング
034.1 JavaScriptの実行と構文
  • 034.1 レッスン 1
034.2 JavaScriptデータ構造
  • 034.2 レッスン 1
034.3 JavaScriptの制御構造と関数
  • 034.3 レッスン 1
  • 034.3 レッスン 2
034.4 WebサイトのコンテンツとスタイリングのJavaScript操作
  • 034.4 レッスン 1
課題 035: NodeJSサーバープログラミング
035.1 NodeJSの基本
  • 035.1 レッスン 1
035.2 NodeJS Expressの基本
  • 035.2 レッスン 1
  • 035.2 レッスン 2
035.3 SQLの基本
  • 035.3 レッスン 1
How to get certified
  1. 課題 034: JavaScriptプログラミング
  2. 034.4 WebサイトのコンテンツとスタイリングのJavaScript操作
  3. 034.4 レッスン 1

034.4 レッスン 1

Certificate:

Web開発の要点

Version:

1.0

Topic:

034 JavaScriptプログラミング

Objective:

034.4 WebサイトのコンテンツとスタイリングのJavaScript操作

Lesson:

1 of 1

はじめに

HTML、CSS、そしてJavaScriptは、Web上で一緒になる3つの異なる技術です。真にダイナミックでインタラクティブなページを作るためには、JavaScriptプログラマはHTMLとCSSのコンポーネントを実行時に組み合わせなければなりません。これは、 Document Object Model (DOM)を使用することで非常に簡単になります。

DOMとのインタラクション

DOMは、ドキュメントに対するプログラミング・インターフェースとして機能するデータ構造で、ドキュメントのあらゆる側面がDOMのノードとして表現され、DOMに加えられた変更は直ちにドキュメントに反映されます。JavaScriptでDOMを使う方法を示すために、以下のHTMLコードを example.html というファイルに保存します。

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8" />
  <title>HTML Manipulation with JavaScript</title>
</head>
<body>

<div class="content" id="content_first">
<p>The dynamic content goes here</p>
</div><!-- #content_first -->

<div class="content" id="content_second" hidden>
<p>Second section</p>
</div><!-- #content_second -->

</body>
</html>

DOMはHTMLが読み込まれてから利用できるようになりますので、以下のJavaScriptをページボディの最後(末尾の </body> タグの前)に記述します。

<script>
let body = document.getElementsByTagName("body")[0];
console.log(body.innerHTML);
</script>

document オブジェクトはDOMの最上位の要素であり、他の全ての要素はそこから分岐しています。 getElementsByTagName() メソッドは、 document から続く、与えられたタグ名を持つ全ての要素を列挙します。文書の中で body タグが一度しか使われていないにもかかわらず、 getElementsByTagName() メソッドは常に見つかった要素の配列のようなコレクションを返すので、最初に(そして唯一)見つかった要素を返すために [0] インデックスを使用します。

HTMLコンテンツ

前の例で示したように、 document.getElementsByTagName("body")[0] が返すDOM要素は、 body 変数に割り当てられました。 body 変数は、そのページのbody要素からすべてのDOMメソッドと属性を継承しているので、body要素を操作するために使用することができます。例えば、 innerHTML プロパティには、対応する要素の内部に書かれたHTMLマークアップコード全体が含まれているので、内部のマークアップを読み取るために使用することができます。 console.log(body.innerHTML) の呼び出しは、 <body></body> 内のコンテンツをWebコンソールに表示します。この変数は、 body.innerHTML = "<p>Content erased</p>" のように、そのコンテンツを置き換えるために使用することもできます。

HTMLマークアップの全体的な部分を変更するよりも、ドキュメントの構造を変更せずに、その要素を操作する方が実用的です。ドキュメントがブラウザによってレンダリングされると、すべての要素がDOMメソッドによってアクセス可能になります。例えば、 document オブジェクトの getElementsByTagName() メソッドで、 * という特別な文字列を使って、すべてのHTML要素をリストアップしてアクセスすることができます。

let elements = document.getElementsByTagName("*");
for ( element of elements )
{
  if ( element.id == "content_first" )
  {
    element.innerHTML = "<p>New content</p>";
  }
}

このコードは document で見つかったすべての要素を elements 変数に格納します。 elements 変数は配列のようなオブジェクトなので、 for ループを使って各項目を繰り返し処理することができます。このコードが実行されているHTMLページに、 id 属性が content_first に設定されている要素があれば(レッスンの最初に示したサンプルHTMLページを参照してください)、 if 文がその要素にマッチして、そのマークアップコンテンツが <p>New content</p> に変更されます。DOM内のHTML要素の属性は、JavaScriptのオブジェクトプロパティの ドット 記法を使ってアクセスできることに注意してください。したがって、 element.id は、 for ループの現在の要素の id 属性を指します。また、 element.getAttribute("id") のように、 getAttribute() メソッドを使用することもできます。

要素のサブセットのみを検査したい場合は、すべての要素を繰り返し調べる必要はありません。例えば、 document.getElementsByClassName() メソッドは、マッチした要素を特定のクラスを持つものに限定します。

let elements = document.getElementsByClassName("content");
for ( element of elements )
{
  if ( element.id == "content_first" )
  {
    element.innerHTML = "<p>New content</p>";
  }
}

しかし、ページ内の特定の要素を変更しなければならない場合、ループを使用して多くのドキュメント要素を繰り返し処理することは最良の戦略ではありません。

特定の要素の選択

JavaScriptには、作業したい要素を正確に選択するための最適化されたメソッドが用意されています。先ほどのループは、 document.getElementById() メソッドで完全に置き換えることができます。

let element = document.getElementById("content_first");
element.innerHTML = "<p>New content</p>";

ドキュメントのすべての id 属性は一意でなければならないので、 document.getElementById() メソッドは単一のDOMオブジェクトのみを返します。JavaScriptではメソッドを直接チェーンすることができるので、 element 変数の宣言も省略することができます。

document.getElementById("content_first").innerHTML = "<p>New content</p>";

getElementById() メソッドは、複雑なドキュメントを扱う際に反復的な手法よりもはるかに優れたパフォーマンスを発揮するので、DOM内の要素を探すのに望ましい手法です。しかし、すべての要素が明示的なIDを持っているわけではなく、このメソッドは、提供されたIDにマッチする要素がない場合には、 null 値を返します(これは、上記の例で使われている innerHTML のように、連鎖した属性や関数を使うこともできません)。さらに、ページの主要な構成要素にのみID属性を割り当て、その子要素を探すためにCSSセレクタを使用するのがより実用的です。

CSSのレッスンで紹介したセレクタは、DOM内の要素にマッチするパターンです。 querySelector() メソッドは、DOMのツリーの中で最初にマッチした要素を返し、 querySelectorAll() は、指定されたセレクタにマッチしたすべての要素を返すようになっています。

前述の例では、 getElementById() メソッドは、 content_first のIDを持つ要素を取得しています。これと同じことを、 querySelector() メソッドでも行うことができます。

document.querySelector("#content_first").innerHTML = "<p>New content</p>";

querySelector() メソッドはセレクタ構文を使用するため、指定されたIDはハッシュ文字で始まる必要があります。一致する要素が見つからない場合は、 querySelector() メソッドは null を返します。

前述の例では、idが content_first のdivのコンテンツ全体が、指定されたテキスト文字列で置き換えられています。この文字列にはHTMLコードが含まれていますが、これはベストプラクティスとは言えません。JavaScriptコードにハードコードされたHTMLマークアップを追加する際には注意が必要です。なぜなら、ドキュメント構造全体の変更が必要になったときに、要素の追跡が困難になる可能性があるからです。

セレクタは要素のIDに限定されません。内部の p 要素を直接指定することができます。

document.querySelector("#content_first p").innerHTML = "New content";

"#content_first p" セレクタは、idが content_first の div 内の最初の p 要素のみにマッチします。最初の要素を操作したい場合には問題なく動作します。しかし、2つ目の段落を変更したい場合もあります。

<div class="content" id="content_first">
<p>Don't change this paragraph.</p>
<p>The dynamic content goes here.</p>
</div><!-- #content_first -->

この場合、 :nth-child(2) 擬似クラスを使って、2番目の p 要素にマッチさせることができます。

document.querySelector("#content_first p:nth-child(2)").innerHTML = "New content";

p:nth-child(2) の数字 2 は、セレクタにマッチする2つ目の段落を示しています。セレクタの詳細や使い方については、CSSセレクタのレッスンをご覧ください。

属性の操作

JavaScriptのDOMとの対話能力は、コンテンツの操作に限定されるものではありません。実際、ブラウザにおけるJavaScriptの最も普及した使い方は、既存のHTML要素の属性を変更することです。

例えば、元のHTMLの例のページに、3つのセクションのコンテンツがあるとします。

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8" />
  <title>HTML Manipulation with JavaScript</title>
</head>
<body>

<div class="content" id="content_first" hidden>
<p>First section.</p>
</div><!-- #content_first -->

<div class="content" id="content_second" hidden>
<p>Second section.</p>
</div><!-- #content_second -->

<div class="content" id="content_third" hidden>
<p>Third section.</p>
</div><!-- #content_third -->

</body>
</html>

一度に1つだけを表示したい場合があるため、すべての div タグには hidden 属性が付いています。これは、例えば、画像のギャラリーから1つの画像だけを表示する場合などに便利です。ページが読み込まれたときにそれらのうちの1つを表示するには、次のようなJavaScriptのコードをページに追加します。

// Which content to show
let content_visible;

switch ( Math.floor(Math.random() * 3) )
{
  case 0:
    content_visible = "#content_first";
  break;
  case 1:
    content_visible = "#content_second";
  break;
  case 2:
    content_visible = "#content_third";
  break;
}

document.querySelector(content_visible).removeAttribute("hidden");

switch 文で評価された式は、0、1、2のいずれかの数字をランダムに返します。対応するIDセレクターは、 content_visible 変数に代入され、 querySelector(content_visible) メソッドで使用されます。連鎖した removeAttribute("hidden") の呼び出しは、要素から hidden 属性を削除します。

逆のアプローチも可能です。すべてのセクションは最初は( hidden 属性なしで)表示されていて、JavaScriptプログラムは content_visible にあるセクション以外のすべてのセクションに hidden 属性を割り当てることができます。そのためには、選択されたものとは異なるすべてのコンテンツdiv要素を繰り返し処理する必要がありますが、これは querySelectorAll() メソッドを使用して行うことができます。

// Which content to show
let content_visible;

switch ( Math.floor(Math.random() * 3) )
{
  case 0:
    content_visible = "#content_first";
  break;
  case 1:
    content_visible = "#content_second";
  break;
  case 2:
    content_visible = "#content_third";
  break;
}

// Hide all content divs, except content_visible
for ( element of document.querySelectorAll(".content:not("+content_visible+")") )
{
  // Hidden is a boolean attribute, so any value will enable it
  element.setAttribute("hidden", "");
}

content_visible 変数が #content_first に設定されていた場合、セレクタは .content:not(#content_first) となり、 content クラスを持つすべての要素のうち、content_first のIDを持つものを除いたもの、と解釈されます。 setAttribute() メソッドは、HTML要素の属性を追加したり変更したりします。このメソッドの最初のパラメータは属性の名前で、2番目のパラメータは属性の値です。

しかし、要素の外観を変更する適切な方法はCSSです。今回の例では、 display CSSプロパティを hidden に設定しましたが、JavaScriptで表示を block に変更しても同じです。

<style>
div.content { display: none }
</style>

<div class="content" id="content_first">
<p>First section.</p>
</div><!-- #content_first -->

<div class="content" id="content_second">
<p>Second section.</p>
</div><!-- #content_second -->

<div class="content" id="content_third">
<p>Third section.</p>
</div><!-- #content_third -->

<script>
// Which content to show
let content_visible;

switch ( Math.floor(Math.random() * 3) )
{
  case 0:
    content_visible = "#content_first";
  break;
  case 1:
    content_visible = "#content_second";
  break;
  case 2:
    content_visible = "#content_third";
  break;
}
document.querySelector(content_visible).style.display = "block";
</script>

HTMLタグとJavaScriptの混在に適用されるグッドプラクティスは、CSSにも適用されます。したがって、JavaScriptのコードの中にCSSのプロパティを直接記述することは推奨されません。その代わり、CSSのルールはJavaScriptのコードとは別に記述する必要があります。ビジュアルスタイリングを交互に行う適切な方法は、要素にあらかじめ定義されたCSSクラスを選択することです。

クラスの操作

要素は複数の関連クラスを持つことができ、必要に応じて追加や削除ができるスタイルを簡単に書くことができます。多くのCSS属性をJavaScriptで直接変更するのは疲れるので、それらの属性を持つ新しいCSSクラスを作成して、そのクラスを要素に追加することができます。DOM要素には classList というプロパティがあり、これを使って対応する要素に割り当てられたクラスを表示したり操作したりすることができます。

例えば、要素の可視性を変更する代わりに、追加のCSSクラスを作成して、 content divを強調することができます。

div.content {
  border: 1px solid black;
  opacity: 0.25;
}
div.content.highlight {
  border: 1px solid red;
  opacity: 1;
}

このスタイルシートは、 content クラスを持つすべての要素に、薄い黒のボーダーと半透明を追加します。また、 highlight クラスを持つ要素のみ、完全に不透明になり、細い赤のボーダーが表示されます。そして、先ほどのようにCSSのプロパティを直接変更するのではなく、選択した要素で classList.add("highlight") メソッドを使用します。

// Which content to highlight
let content_highlight;

switch ( Math.floor(Math.random() * 3) )
{
  case 0:
    content_highlight = "#content_first";
  break;
  case 1:
    content_highlight = "#content_second";
  break;
  case 2:
    content_highlight = "#content_third";
  break;
}

// Highlight the selected div
document.querySelector(content_highlight).classList.add("highlight");

これまで見てきたテクニックや例は、すべてページ読み込みの最後に行われたものでしたが、この段階に限定されるものではありません。実際、JavaScriptがWeb開発者にとって便利なのは、次に紹介するようなページ上のイベントに反応する能力です。

イベントハンドラー

すべての可視ページ要素は、クリックやマウスの動きなどのインタラクティブなイベントの影響を受けます。これらのイベントにカスタムアクションを関連付けることで、HTMLドキュメントのできることが大きく広がります。

関連付けられたアクションの恩恵を受ける最も明白なHTML要素は、おそらく button 要素でしょう。その仕組みを説明するために、サンプルページの最初の div 要素の上に、3つのボタンを追加してみましょう。

<p>
<button>First</button>
<button>Second</button>
<button>Third</button>
</p>

<div class="content" id="content_first">
<p>First section.</p>
</div><!-- #content_first -->

<div class="content" id="content_second">
<p>Second section.</p>
</div><!-- #content_second -->

<div class="content" id="content_third">
<p>Third section.</p>
</div><!-- #content_third -->

ボタンはそれだけでは何もしませんが、押されたボタンに対応する div をハイライトしたいとします。そこで、 onClick 属性を使って、それぞれのボタンにアクションを関連付けることができます。

<p>
<button onClick="document.getElementById('content_first').classList.toggle('highlight')">First</button>
<button onClick="document.getElementById('content_second').classList.toggle('highlight')">Second</button>
<button onClick="document.getElementById('content_third').classList.toggle('highlight')">Third</button>
</p>

classList.toggle() メソッドは、指定したクラスが要素に存在しない場合は追加し、既に存在する場合は削除します。この例を実行すると、複数の div が同時にハイライトされることに気づくでしょう。押されたボタンに対応する div だけをハイライトするには、他の div 要素から highlight クラスを削除する必要があります。とはいえ、カスタムアクションが長すぎたり、1行以上のコードが必要な場合は、要素タグとは別に関数を書いたほうが実用的です。

function highlight(id)
{
  // Remove the "highlight" class from all content elements
  for ( element of document.querySelectorAll(".content") )
  {
    element.classList.remove('highlight');
  }

  // Add the "highlight" class to the corresponding element
  document.getElementById(id).classList.add('highlight');
}

前述の例と同様に、この関数は <script> タグの中や、ドキュメントに関連付けられた外部のJavaScriptファイルの中に置くことができます。 highlight 関数は、まず、 content クラスに関連付けられたすべての div 要素から highlight クラスを削除し、次に、選択した要素に highlight クラスを追加します。そして、それぞれのボタンは、対応するid属性を関数の引数として用いて、その onClick 属性からこの関数を呼び出す必要があります。

<p>
<button onClick="highlight('content_first')">First</button>
<button onClick="highlight('content_second')">Second</button>
<button onClick="highlight('content_third')">Third</button>
</p>

onClick 属性に加えて、 onMouseOver 属性(ポインティングデバイスを使ってカーソルが要素の領域内へ移動したときにトリガーされる)、 onMouseOut 属性(ポインティングデバイスが要素の領域外に出たときにトリガーされる)などを使用することができます。さらに、イベントハンドラはボタンに限定されませんので、表示されているすべてのHTML要素について、これらのイベントハンドラにカスタムアクションを割り当てることができます。

演習

  1. document.getElementById() メソッドを使って、id属性が message である要素のインナーコンテンツに “Dynamic content” というフレーズを挿入するにはどうしたらいいでしょうか?

  2. document.querySelector() メソッドで要素のIDを参照する場合と、 document.getElementById() メソッドで要素を参照する場合の違いは何ですか?

  3. classList.remove() メソッドの目的は何ですか?

  4. myelement.classList.toggle("active") メソッドで、 myelement に active クラスが割り当てられていない場合、どのような結果になりますか?

発展演習

  1. document.querySelectorAll() メソッドにどのような引数を与えれば、 document.getElementsByTagName("input") メソッドを模倣することができるでしょうか?

  2. classList プロパティを使って、与えられた要素に関連するすべてのクラスをリストアップするにはどうしたらいいでしょうか?

まとめ

このレッスンでは、JavaScriptを使って、DOM(Document Object Model)を利用して、HTMLのコンテンツやそのCSSプロパティを変更する方法を説明しました。これらの変更は、ユーザーイベントによって引き起こされることができ、動的なインターフェースを作成するのに便利です。このレッスンでは、以下の概念と手順を説明しました。

  • document.getElementById() 、 document.getElementsByClassName() 、 document.getElementsByTagName() 、 document.querySelector() そして document.querySelectorAll() などのメソッドを使用して、ドキュメントの構造を検査する方法

  • innerHTML プロパティを使ってドキュメントのコンテンツを変更する方法

  • メソッド setAttribute() と removeAttribute() を使用して、ページ要素の属性を追加および変更する方法

  • classList プロパティを使用して、要素のクラスを操作する適切な方法と、CSS スタイルとの関係

  • 特定の要素のマウスイベントに関数をバインドする方法

演習の回答

  1. document.getElementById() メソッドを使って、id属性が message である要素のインナーコンテンツに “Dynamic content” というフレーズを挿入するにはどうしたらいいでしょうか?

    それは innerHTML プロパティで実現できます。

    document.getElementById("message").innerHTML = "Dynamic content"
  2. document.querySelector() メソッドで要素のIDを参照する場合と、 document.getElementById() メソッドで要素を参照する場合の違いは何ですか?

    document.querySelector() などのセレクタを使用する関数では、id属性の指定にハッシュ文字(#)を付加する必要があります。

  3. classList.remove() メソッドの目的は何ですか?

    これは、対応する要素の class 属性から、(関数の引数として名前が与えられた)クラスを削除します。

  4. myelement.classList.toggle("active") メソッドで、 myelement に active クラスが割り当てられていない場合、どのような結果になりますか?

    このメソッドは myelement に active クラスを割り当てます。

発展演習の回答

  1. document.querySelectorAll() メソッドにどのような引数を与えれば、 document.getElementsByTagName("input") メソッドを模倣することができるでしょうか?

    document.querySelectorAll("input") を使うと、 document.getElementsByTagName("input") と同様に、ページ内のすべての input 要素にマッチします。

  2. classList プロパティを使って、与えられた要素に関連するすべてのクラスをリストアップするにはどうしたらいいでしょうか?

    classList プロパティは、配列のようなオブジェクトなので、 for ループを使って、含まれるすべてのクラスを繰り返し処理することができます。

Linux Professional Insitute Inc. All rights reserved. 学習資料をご覧ください: https://learning.lpi.org
ここでの作成物は、Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International Licenseの下でライセンスされています。

次のレッスン

035.1 NodeJSの基本 (035.1 レッスン 1)

次のレッスンを読む

Linux Professional Insitute Inc. All rights reserved. 学習資料をご覧ください: https://learning.lpi.org
ここでの作成物は、Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International Licenseの下でライセンスされています。

LPIは非営利団体です。

© 2023 Linux Professional Institute(LPI)は、オープンソースプロフェッショナル向けのグローバルな認定基準およびキャリアサポート組織です。200,000人以上の認定保持者を擁する、世界初かつ最大のベンダー中立Linuxおよびオープンソース認定機関です。LPIは180か国以上で認定プロフェッショナルを擁し、複数の言語で試験を実施し、何百ものトレーニングパートナーを擁しています。

私たちの目的は、オープンソースの知識とスキルの認定資格を世界中からアクセスできるようにすることで、誰にとっても経済的で創造的な機会を可能にすることです。

  • LinkedIn
  • flogo-RGB-HEX-Blk-58 Facebook
  • Twitter
  • お問い合わせ
  • 個人情報とCookieポリシー

間違いを見つけたり、このページを改善したいですか? 私たちに知らせてください。.

© 1999–2023 The Linux Professional Institute Inc. All rights reserved.