HTML Living Standard  第3部 Javascript 8 ブラウザオブジェクト


 

8 ブラウザオブジェクト

ブラウザに表示されるドキュメントや画像、フォームなどブラウザを構成する各部品をブラウザオブジェクトといいます。

ブラウザオブジェクトは標準の規格があるわけではなく、個々のブラウザごとに独自に実装されています。(その中の Document オブジェクトは、ドキュメントオブジェクトモデル:DOM としてほぼ標準化されています。)そのため以前はブラウザごとの仕様の違いによりクロスブラウザ問題がありましたが、現在では主要なブラウザではそれなりに互換性を持っています。

8.1  ウィンドウ(Window)

ドキュメントを表示するウィンドウに対応するのが Window オブジェクトです。

Window オブジェクトには、document プロパティや location プロパティなどがあり、document プロパティは、対応するウィンドウに関連付けられた Document オブジェクトを参照し、location プロパティは、対応するウィンドウに関連付けられた Location オブジェクトを参照します。また、自身を参照する window プロパティもあります。

Window オブジェクトの主なプロパティとメソッドについて説明します。<script>~</script> の間では Window. を省略することができ、Window.window.~ ではなく window.~ というように参照することができます。

注意

別ウィンドウを開こうとしても、タブとして開くよう設定されているブラウザがあります。その場合は設定を変更したり、コンテキストメニュー(右クリックメニュー)からウィンドウを開く必要があります。

[設定]-[一般]-[タブグループ]  「新しいウィンドウではなく新しいタブに開く(W)」のチェックを外してから、実行する
タブで開いた後、タブのコンテキストメニューで、「ポップアップウィンドウで開く(S)」を選択する
ただし、その場合親ウィンドウへの参照は行われない

8.1.1  ウィンドウ情報

(1)ウィンドウ情報

ウィンドウに関する主な情報です。

プロパティ
nameR/Oウィンドウの名前
opener自身を window.open したウィンドウのオブジェクト
parentR/O親ウィンドウ(iframe 内から見た iframe タグを含むウィンドウ)のオブジェクト
selfR/O自身のウィンドウオブジェクト
記述例
parent
<span id="element">PARENT</span>
child
<span id="element">CHILD</span>
<div id="d1"></div>
<!-- 以下略 -->

<script>
  document.getElementById("d1").textContent = window.name;
  document.getElementById("d2").textContent = window.self.name;
  if (window.opener != undefined) {
    document.getElementById("d3").textContent = window.opener.name;
    document.getElementById("d4").textContent = window.opener.document.getElementById("element").textContent;
  }
  document.getElementById("d5").textContent = window.parent.name;
  document.getElementById("d6").textContent = window.parent.document.getElementById("element").textContent;
</script>

下の実行例では iframe で表示している(グレイの枠内)ため、親子関係があり parent の情報が表示されています。また、ウィンドウを開いていないため、ウィンドウの名前も opener も設定されていません。

しかし、「別ウィンドウで開く」ボタンをクリックした場合は、ウィンドウに名前が付けられていて、opener も(「別ウィンドウで開く」ボタンのある)このウィンドウが設定されています。また parent はありませんので、開かれた child ウィンドウ自身が設定されます。

では、タブのコンテキストメニューで「ポップアップウィンドウで開く(S)」を選択してウィンドウとして開くことはできますが、ウィンドウの名前も opener も設定されないようです。

実行例
PARENT  ← parent のエレメント


別ウィンドウで開く

(2)位置、サイズ

ウィンドウの位置やサイズに関する主な情報です。

プロパティ
innerWidthウィンドウ内側の幅(iframe の場合は iframe の width)
innerHeightウィンドウ内側の高さ(iframe の場合は iframe の height)
outerWidthR/Oウィンドウ外側の幅
outerHeightR/Oウィンドウ外側の高さ
pageXOffsetR/O水平スクロールされているピクセル数
pageYOffsetR/O垂直スクロールされているピクセル数
screenXR/O(メイン)画面の左端からブラウザの左端までの水平方向の距離
screenYR/O(メイン)画面の上端からブラウザの上端までの垂直方向の距離
screen.width × screen.height R/Oウィンドウの中央があるディスプレイの幅 × 高さ
screen.availWidth × screen.availHeight R/Oウィンドウの中央があるディスプレイの有効領域(タスク・バーなどがある場合それらを省いた領域)の幅 × 高さ

また、screenX や screenY は、メインディスプレイの左上からの位置が設定されます。したがって、メインディスプレイの上や左に他のディスプレイが配置されているような場合には負の値になることもあります。

記述例
<div id="d1"></div>
<!-- 以下略 -->

<script>
  document.getElementById("d1").textContent = window.screen.width + "×" + window.screen.height;
  document.getElementById("d2").textContent = window.screen.availWidth + "×" + window.screen.availHeight;
  document.getElementById("d3").textContent = window.outerWidth + "×" + window.outerHeight;
  document.getElementById("d4").textContent = window.innerWidth + "×" + window.innerHeight;
  document.getElementById("d5").textContent = window.screenX + "×" + window.screenY;
  document.getElementById("d6").textContent = window.pageXOffset + "×" + window.pageYOffset;
</script>

innerWidth×innerHeight は、下の実行例では iframe で表示しているため iframe のサイズになっています。別ウィンドウで開けば実際のウィンドウの内側のサイズになります。

では、コンテキストメニューで、「ポップアップウィンドウで開く」を選択するとウィンドウが開きます。

(3)ウィンドウの状態

プロパティ
closedR/Oウィンドウの状態(true:閉、false:開)
記述例
<div id="d1"></div>
<!-- 以下略 -->

<script>
  var w = null;
  this.display = function() {
    if (w != null)
      document.getElementById("d1").textContent = w.closed;
  }
</script>

closed は、ウィンドウが開いていれば false、閉じていれば true になります。したがって、「ウィンドウを開く」ボタンで別のウィンドウが開くと false、「ウィンドウを閉じる」ボタンでウィンドウが閉じると true になります。

では、別タブとして開きますが、closed は正しく設定されるようです。

実行例


8.1.2  ウィンドウ制御

(1)ウィンドウを開く

ウィンドウを開きます。

window.open('url', 'name' [, 'style'])

ウィンドウを開く。

多くのブラウザでは、ウィンドウはメインディスプレイの指定位置に開くが、は同じウィンドウの別タブに開く。

引数 url:開こうとするページのアドレス

引数 name:ウィンドウの名前

引数 style:ウィンドウの特性(特性=値 で指定する。複数ある場合は , で区切る)

主な特性機能
top数値ウィンドウの上側位置(注1)×
left数値ウィンドウの左側位置(注3)(注1)×
height数値コンテンツエリアの高さ(水平スクロールバーの高さを含む)(注1)×
width数値コンテンツエリアの幅(垂直スクロールバーの幅を含む)(注1)×
popupyes|no別ウィンドウで開く(yes)、別タブで開く(no)(注2)(規定値:no)××
noopeneryes|no親ウィンドウへの参照可(yes)、不可(no)
不可の場合 opener が null になる(規定値:no)
noreferreryes|noReferer ヘッダーの参照可(yes)、不可(no)
yes の場合 noopener も yes になる(規定値:no)
(注1)規定値(+ は親ウィンドウの値に加算)

top+10+10+221360
left+10+10+242480
height+70+65+0534+0
width+26+16+0705+0
指定した大きさで表示される最小サイズ

height100 99100 90 34
width177129120270134

(注2)は、popup を指定しなくても、別ウィンドウで開く


(注3)ブラウザが、左右に並べたマルチディスプレイの右ディスプレイにある場合は次のようになる
表示ディスプレイ
noopener = no右ディスプレイに表示された場合右ディスプレイの左端になる
noopener = yes右ディスプレイの左端から left の位置に表示される

戻り値:ウィンドウオブジェクト


記述例
var w = window.open("xxx.htm","sample","width=300,height=200,popup=yes");

主なスタイルを指定してみます。

実行例

ただし、同じ width、height を指定しても実際に開くウィンドウの大きさはブラウザによって異なります。

下の例はすべて Windows10 で height=150,width=350 で開いています。赤い線がその大きさです。

そして、表示されている数値が実際のコンテンツエリアの大きさです。(以外は正しくないようです。)

記述例
<script>
window.open("openWinS.htm","sample","left=300,top=300,height=150,width=350")
</script>




は、タブ表示された後、「ポップアップウィンドウで開く(S)」を選択して表示しています。ウィンドウの大きさは直前に開いていたウィンドウと同じになるようです。


(2)ウィンドウを閉じる

ウィンドウを閉じます。

ウィンドウオブジェクト.close()

window.open メソッドで開いたウィンドウを閉じる。window.close() とすると、自身のウィンドウを閉じる。

戻り値:なし

記述例
var w = window.open("xxx.htm", "sample");
w.close();

(3)ウィンドウの移動

ウィンドウを移動します。

ウィンドウオブジェクト.moveTo(x, y)、ウィンドウオブジェクト.moveBy(x, y)

window.open メソッドで開いたウィンドウを移動する。

引数 x:移動先の x 座標(moveTo)、x 方向への移動量(moveBy)

引数 y:移動先の y 座標(moveTo)、y 方向への移動量(moveBy)

戻り値:なし

記述例
var w = window.open("xxx.htm", "sample");
w.moveTo(100, 200);     // (100, 200) へ移動
w.moveBy(10, 0);        // 右へ 10 ピクセル移動
w.close();

開いたウィンドウを移動させます。

実行例

(4)ウィンドウサイズの変更

ウィンドウの大きさを変更します。

ウィンドウオブジェクト.resizeTo(x, y)、ウィンドウオブジェクト.resizeBy(x, y)

window.open メソッドで開いたウィンドウの大きさを変更する。

引数 x:幅(resizeTo)、幅の増加量(resizeBy)

引数 y:高さ(resizeTo)、高さの増加量(resizeBy)

戻り値:なし

記述例
var w = window.open("xxx.htm", "sample");
w.resizeTo(100, 200);     // 幅 100 ピクセル、高さ 200 ピクセルの大きさに変更
w.resizeBy(10, 0);        // 幅を 10 ピクセル拡大
w.close();

開いたウィンドウの大きさを変更します。

実行例

(5)ウィンドウ内容のスクロール

ウィンドウの内容をスクロールします。

ウィンドウオブジェクト.scrollTo(x, y)、ウィンドウオブジェクト.scrollBy(x, y)

window.open メソッドで開いたウィンドウの内容をスクロールする。

引数 x:スクロール先の x 座標(scrollTo)、x 方向へのスクロール量(scrollBy)

引数 y:スクロール先の y 座標(scrollTo)、y 方向へのスクロール量(scrollBy)

戻り値:なし

記述例
var w = window.open("xxx.htm", "sample");
w.scrollTo(100, 200);     // (100, 200) へ スクロール
w.scrollBy(10, 0);        // 右へ 10 ピクセル スクロール
w.close();

開いたウィンドウの内容をスクロールします。

実行例

(6)ウィンドウのフォーカス

ウィンドウにフォーカスを合わせたり、はずしたりします。

ウィンドウオブジェクト.focus()、ウィンドウオブジェクト.blur()

window.open メソッドで開いたウィンドウにフォーカスを合わせる/はずす。

戻り値:なし

記述例
var w = window.open("xxx.htm", "sample");
w.focus();     // フォーカスを合わせる
w.blur();      // フォーカスをはずす
w.close();

開いたウィンドウにフォーカスします(ブラウザによってはポップアップ画面がブロックされるかもしれないので許可してやってください)。

実行例

では、別タブとして開きますが、フォーカスは正しく当たるようです。


8.1.3  ダイアログ表示

(1)警告ダイアログ

window.alert(message)

[OK]ボタン付きの警告ダイアログを表示する。

引数 message:表示する文字列

戻り値:なし

記述例
window.alert("メッセージ");
実行例

(2)確認ダイアログ

window.confirm(message)

[OK]ボタンと[キャンセル]ボタンが付いている確認ダイアログを表示する。

引数 message:表示する文字列

戻り値:[OK]が true、[キャンセル]が false

記述例
var r = window.confirm("メッセージ");

戻り値は、[OK]ボタンのときは true、[キャンセル]ボタンのときは false になります。

実行例

(3)文字列入力ダイアログ

window.prompt(message[, init])

文字列入力ダイアログを表示する。

引数 message:表示する文字列

引数 init:初期値

戻り値:入力された文字列、[キャンセル]のときは null

記述例
var r = window.prompt("メッセージ", "初期値");

戻り値は、[OK]ボタンのときは入力した文字列、[キャンセル]ボタンのときは null になります。

実行例

8.1.4  タイマー

(1)タイマー

タイマーを設定、解除します。

window.setTimeout(func, msec[, arg1[, arg2, ...]])

msec ミリ秒後に func を実行する。

引数 func:関数("" で囲むか、() を付けないで関数名のみを記述)

引数 msec:ミリ秒

引数 arg1, arg2:func で指定した関数の引数

戻り値:タイマーID(正の整数)


window.clearTimeout(timer)

タイマーを解除する。

引数 timer:タイマーID

戻り値:なし

記述例
var tm;        // タイマーID
tm = window.setTimeout("now()", 3000);     // タイマーを設定する
window.clearTimeout(tm);                   // タイマーを解除する

[set] ボタンをクリックすると3秒後に別途定義されている now() が呼び出され、現在時刻が表示されます。3秒の間に [reset] ボタンをクリックするとタイマーが解除されます。

実行例

setTimeout の最初の引数として "now()" としていますが、これは now でも構いません。ただし、now() としてしまうと、すぐに now() が実行されてしまいます。


(2)定期実行

定期的に実行するタイマーを設定、解除します。

window.setInterval(func, msec[, arg1[, arg2, ...]])

msec ミリ秒毎に func を定期的に実行する。

引数 func:関数("" で囲むか、() を付けないで関数名のみを記述)

引数 msec:ミリ秒

引数 arg1, arg2:func で指定した関数の引数

戻り値:インターバルID(正の整数)


window.clearInterval(timer)

タイマーを解除する。

引数 timer:インターバルID

戻り値:なし

記述例
var tm;        // インターバルID
tm = window.setInterval("now()", 1000);     // タイマーを設定する
window.clearInterval(tm);                   // タイマーを解除する

[set] ボタンをクリックすると毎秒別途定義されている now() が呼び出され、現在時刻が表示されます。[reset] ボタンをクリックするとタイマーが解除されます。

実行例

setInterval の最初の引数として "now()" としていますが、これは now でも構いません。ただし、now() としてしまうと、すぐに now() が実行されてしまいます。


(3)アニメーション用タイマー

ブラウザの更新準備ができたら func を実行します。タブやブラウザウィンドウがアクティブでなかったら実行する頻度を落とします。主にアニメーションを更新するときに使用します。

ただし、自動的に繰り返し実行されるわけではなく、func の中で次の実行のために毎回 requestAnimationFrame で func を設定する必要があります。

(setInterval や setTimeout は常に指定された時間で実行します。)

window.requestAnimationFrame(func)

ブラウザの準備ができたら func を実行する。

引数 func:関数

戻り値:リクエストID


window.cancelAnimationFrame(requestID)

コールバック関数(func)の更新を中止する。

引数 requestID:リクエストID

戻り値:なし

記述例
var requestId;
function now() {
  requestId = window.requestAnimationFrame(now);
  var t = new Date();
  document.getElementById('x').textContent=t.toLocaleDateString() + " " + t.toLocaleTimeString();
}
requestId = window.requestAnimationFrame(now);

[set] ボタンをクリックすると現在時刻が表示されます。時刻の更新は一定時間ごとではなく更新準備ができるごとに表示されます。[reset] ボタンをクリックするとタイマーが解除されます。

実行例

8.1.5  イベント

ウィンドウに対して、いろいろな操作(マウスを重ねる、クリックするなど)をしたり、ウィンドウが変化(サイズが変わる、ドキュメントが読み込まれるなど)すると、その都度イベントが発生しています。

発生したイベントに対して処理を行いたいときに、イベントと関数を関連付けます。

イベントリスナーを設定、解除します。なお、第3引数の useCapture については、「10.2  イベントの伝播」を参照してください。

window.addEventListener(event, func, useCapture)

event 発生時に func を実行するようにイベントリスナーを設定する。

引数 event:イベントの種類

引数 func:関数

引数 useCapture:Capture(捕捉)フェーズを使用する(true)、使用しない(false) 規定値

戻り値:なし


window.removeEventListener(event, func, useCapture)

指定した引数とまったく同じである、イベントリスナーを削除する。ただし、addEventListener のとき、第二引数に直接メソッドを記述していた場合は削除できない。

引数 event:イベントの種類

引数 func:関数

引数 useCapture:Capture(捕捉)フェーズを使用する(true)、使用しない(false) 規定値

戻り値:なし

記述例
<script>
function add() {
  window.addEventListener('click', now, false);
}
function remove() {
  document.getElementById('x').textContent="";
  window.removeEventListener('click', now, false);
}
function now() {
  let t = new Date();
  document.getElementById('x').textContent=t.toLocaleDateString() + " " + t.toLocaleTimeString();
}
</script>

<div onClick='add();'>addEventListener</div> <div onClick='remove();'>removeEventListener</div>
<span id='x'></span>

[addEventListener] ボタンで、クリックで時刻が表示されるようイベントリスナーを設定します。[removeEventListener] ボタンで、イベントリスナーを解除します。

[addEventListener] ボタンクリック後に、ボタン下部のどこかをクリックしてください。時刻が変わります。

実行例

8.1.6  メッセージ

別ウィンドウにメッセージを伝達します。

通常、異なった複数のページでのスクリプトはそれらが実行されたページが同じプロトコル、ポート番号、ホストである場合に限りお互いにアクセスすることが可能です。

ウィンドウオブジェクト.postMessage(message, targetOrigin)

ウィンドウオブジェクトにメッセージを伝達する。

targetOrigin が * でない URI の場合、ウィンドウオブジェクトと一致しなければ伝達されない。

引数 message:メッセージ

引数 targetOrigin:メッセージの伝達先の URI(特に指定しない場合は *)

戻り値:なし

記述例
  <script>
  function send() {
    var val = F1.message.value;
    var iframe = document.getElementById('other');
    iframe.contentWindow.postMessage(val,'*');
  }
  </script>

  <form name="F1" action="#">
    <input type="text" name="message" value="メッセージ"> <span class="switch" onclick="send();">送信</span>
  </form>
  <br>
  <iframe src="other.htm" id="other" frameborder="1px" width="600px" height="60px"></iframe>
other.htm
  <div id="d"></div>

  <script>
    window.addEventListener('message', function(event){
      document.getElementById('d').textContent = event.data;
    });
  </script>

iframe 内の HTML にメッセージが伝達されます。伝達された側には message イベントが発生します。

実行例

8.1.7  エンコードとデコード

バイナリデータなどと base64 エンコードされた文字列との間で変換します。

そのまま送信すると問題を起こす可能性のあるデータを送信できる文字列にエンコードします。また、その逆にエンコードされた文字列を元のバイナリデータにデコードします。

base64 とは、64種類の印字可能な英数字(1文字6ビット)のみを用いて表すエンコード方式で、それ以外の文字を扱うことの出来ない通信環境にてマルチバイト文字やバイナリデータを扱うためのものです。

(1)エンコード

バイナリデータなどから base64 エンコードされた文字列を作成します。

ただし、ユニコードの文字列の場合は、ほとんどのブラウザで例外が発生します。

window.btoa(binary)

バイナリデータなどから base64 エンコードされた文字列を作成する。

引数 binary:バイナリデータ

戻り値:base64 エンコードされた文字列

ユニコードの文字列の場合は、ほとんどのブラウザで例外が発生します(二つ目の例)。その場合は三つ目の例のような記述が必要です。

四つ目の例は画像データをエンコードしています。ただし、最初の42文字だけを表示しています。

記述例
<span id="d01"></span><br>
<!-- 以下略 -->

<script>
document.getElementById('d01').textContent = window.btoa("ABCDE");
try {
  document.getElementById('d02').textContent = window.btoa("あいうえお");
}
catch(e) {
  document.getElementById('d02').textContent = e;
}
document.getElementById('d03').textContent = encode("あいうえお");

function encode(str) {
  return window.btoa(unescape(encodeURIComponent(str)));
}

function enc() {
  var canvas = document.createElement("canvas");
  canvas.width = 74;
  canvas.height = 74;
  var context = canvas.getContext("2d") ;
  context.drawImage(image, 0, 0, 74, 74);
  if (canvas.toBlob != undefined)
    canvas.toBlob(function(result) { set(result); });
  else
    set(canvas.msToBlob());
}

function set(bin) {
  var file = new Blob([bin], {'type':'image/png'});
  var reader = new FileReader();
  reader.onload = function() {
    var arr = new Uint8Array(reader.result);      // 8ビット符号なし整数値の配列
    var b = "";
    for(var i = 0 ; i < 42 ; i++) {      // 最初の42文字だけを表示
      b += String.fromCharCode(arr[i]);      // UTF-16 文字列に変換
    }
    document.getElementById('d04').textContent = window.btoa(b);      // base64にエンコード
  }
  reader.readAsArrayBuffer(file);
}
</script>
<img id="image" src="bear.png" onload="enc();"><span id="d04"></span><br>

ユニコードの文字列のエンコードでは、ほとんどのブラウザで例外が発生します(二つ目の例)。

実行例

(2)デコード

base64 エンコードされた文字列からバイナリデータなどを作成します。

window.atob(encoded)

base64 エンコードされた文字列からバイナリデータなどを作成する。

引数 encoded:base64 エンコードされた文字列

戻り値:デコードされた元のデータ

二つ目の例の結果は、「(1)エンコード」で "あいうえお" をエンコードしたときに使用した unescape(encodeURIComponent("あいうえお")) そのものです。

よって、unescape(encodeURIComponent()) の逆のことをしなければ、"あいうえお" になりません。それが3つ目の例です。

四つ目の例は、エンコードされた画像データですが、ここではバイナリ値に変換しているのではなく、img 要素の src 属性に "data:image/png;base64," に続いて指定することで画像を表示しています。ちなみに下の例の画像は base64 エンコードされた文字列として 11256文字になります(記述例では省略してあります)。

記述例
<span id="d01"></span><br>
<!-- 以下略 -->
<img id="d04">

<script>
document.getElementById('d01').textContent = window.atob("QUJDREU=");
document.getElementById('d02').textContent = window.atob("44GC44GE44GG44GI44GK");
document.getElementById('d03').textContent = decode("44GC44GE44GG44GI44GK");
document.getElementById('d04').src = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEoAAABKCAYAAAAc ...";

function decode(str) {
  return decodeURIComponent(window.atob(str).split('').map(function(c) {
        return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);      // %E3%81%82 のような形式に変換
    }).join(''));
}
</script>
実行例

navigator オブジェクトを用いることで、スクリプトを実行しているアプリケーションについての情報を得ることができます。


navigator オブジェクトの主なプロパティとメソッドについて説明します。

プロパティ
appCodeNameR/Oブラウザの内部 "コード" ネーム
appNameR/Oブラウザの正式名称
appVersionR/Oブラウザのバージョン
userAgentR/Oブラウザに関する情報

記述例
<div id="d1"></div>
<!-- 以下略 -->

<script>
window.addEventListener('load', function() {
  document.getElementById("d1").textContent=navigator.appCodeName;
  document.getElementById("d2").textContent=navigator.appName;
  document.getElementById("d3").textContent=navigator.appVersion;
  document.getElementById("d4").textContent=navigator.userAgent;
}, false);
</script>
実行例
ブラウザによる違い
 appCodeNameappNameappVersionuserAgent
MozillaNetscape5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36 Edg/123.0.0.0Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36 Edg/123.0.0.0
MozillaNetscape5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36
MozillaNetscape5.0 (Windows)Mozilla/5.0 (Windows NT 10.0; rv:124.0) Gecko/20100101 Firefox/124.0
MozillaNetscape5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36 OPR/109.0.0.0Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36 OPR/109.0.0.0
MozillaNetscape 5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36 Sleipnir/6.5.5Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36 Sleipnir/6.5.5
MozillaNetscape5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36

ブラウザの区別に使えそうな文字列を赤字で示してみました。なお、 は区別できないかもしれません。


ブラウザの判定順
1."Edg" → Edge
2."Firefox" → Firefox
3."OPR" → Opera
4."Sleipnir" → Sleipnir

8.3  ヒストリ(History)

history オブジェクトを用いることで、ブラウザの履歴についての情報を得たり、履歴リストの中の URL のページへ移動することなどができます。


history オブジェクトの主なプロパティとメソッドについて説明します。

8.3.1  ヒストリ情報

プロパティ
lengthR/Oブラウザの履歴リストの中の URL の数
記述例
<div id="d1"></div>

  <script>
  window.addEventListener('load', function() {
    document.getElementById("d1").textContent=history.length;
  }, false);
  </script>
実行例

8.3.2  移動

back()、forward() は、ブラウザの「戻る」「進む」と同様の機能になります。

history.forward()

ブラウザの履歴リストの中の次の URL に移動する。go(1) と同じ。

戻り値:なし


history.back()

ブラウザの履歴リストの中の前の URL に移動する。go(-1) と同じ。

戻り値:なし


history.go(number)

ブラウザの履歴リストの number 個先のページに移動する。

引数 number:履歴リスト中の番号(負の場合は前に、正の場合は次に移動する)

戻り値:なし

記述例(ヒストリのボタン)
<div class="switch" onclick="history.back()"></div>
<div class="switch" onclick="history.forward()"></div>

まず、⇨ ボタンで、赤⇨緑⇨青の順に移動させてページをヒストリに残してください。

その後、⇷ ⇸ ボタンでヒストリを移動させてください。

実行例

8.3.3  変更


(1) 履歴の追加

history.pushState(state, title[, url])

ブラウザの履歴を追加する。ただし、指定したURLの再読み込みは発生しないので、ページも遷移しない。

引数 state:状態と関連付けされた情報

引数 title:タイトル

引数 url:ブラウザに表示される URI規定値:現在の URL

戻り値:なし

次の例は、[戻る]ボタンをクリックしても、履歴に追加されている自分自身に戻ることになります。

記述例
  <script>
    history.pushState({}, null);      // 第3引数を省略すると、自分自身を履歴に追加

    window.addEventListener("popstate", function() {  // ブラウザの「戻る」「進む」ボタンで発生するイベント
      history.pushState({}, null);
    });
  </script>

実行例をクリックしてください。別ウィンドウで「ヒストリ 1」を開きます。

その後、[⇨ ヒストリ 2] ボタンで「ヒストリ 2」へ移動させてください。「ヒストリ 2」では、履歴に自分自身(ヒストリ 2)を追加します。

「ヒストリ 2」では、ブラウザの[戻る]ボタンで「ヒストリ 1」には戻れません。履歴にある自分自身(ヒストリ 2)に移動します(つまり移動しない)。

もちろん、[⇨ ヒストリ 1] ボタンでは「ヒストリ 1」へ移動できます。また、「ヒストリ 1」のブラウザの[戻る]ボタンでも「ヒストリ 2」に戻れます。

ただし、以外は「ヒストリ 2」で、いきなり[戻る]ボタンをクリックすると「ヒストリ 1」に戻れてしまいます(なぜだかわかりません)。[戻る]ボタンをクリックする前に緑色の背景部分をクリックしてみてください。そうすると[戻る]ボタンでは「ヒストリ 1」には戻れなくなります。

実行例 (別ウィンドウで開きます)


(2) 履歴の置き換え

history.replaceState(state, title, url)

現在のセッション履歴を置き換える。

引数 state:状態と関連付けされた情報

引数 title:タイトル

引数 url:移動先の URI

戻り値:なし

[戻る]ボタンをクリックしても、履歴が変更されているため、変更されたページに移動することになります。

記述例(b2.htm)
  <script>
    history.replaceState(null, null, 'b1.htm');      // 履歴を変更
  </script>

実行例をクリックしてください。別ウィンドウで「ヒストリ 1」を開きます。

その後、[⇨ ヒストリ 2] ボタンで「ヒストリ 2」へ移動させ、さらに[⇨ ヒストリ 3] ボタンで「ヒストリ 3」へ移動させてください。

「ヒストリ 2」では、履歴を「ヒストリ 1」に変更しています。そのため、「ヒストリ 3」では、ブラウザの[戻る]ボタンで「ヒストリ 2」ではなく、「ヒストリ 1」に戻ることになります。

実行例 (別ウィンドウで開きます)


8.4  ロケーション(Location)

location オブジェクトを用いることで、現在表示しているアドレス(URL)に関する情報を得ることができます。


location オブジェクトの主なプロパティとメソッドについて説明します。

8.4.1  ロケーション情報

プロパティ
href指定したURLへ移動、もしくは現在表示しているページのアドレス(URL)
protocolURL のプロトコル
hostホスト名とポート番号
hostnameホスト名
portポート番号
pathnameパス
searchURLの ? 以降の部分
hashURLの # 以降の部分

実行例

8.4.2  移動

location.assign(url)

指定したURLへ移動する。履歴は追加される(現在のページは記録される)

引数 url:移動するドキュメントの URL

戻り値:なし


location.replace(url)

指定したURLへ移動する。履歴は上書きされる(現在のページは記録されない)

引数 url:移動するドキュメントの URL

戻り値:なし

記述例
(2) のソース
  <div class="switch"
     onclick="location.assign('a3.htm');">go</div>
(2) のソース
  <div class="switch"
     onclick="location.replace('b3.htm');">go</div>
(3) のソース
  <div class="switch"
     onclick="history.back();">back</div>
(3) のソース
  <div class="switch"
     onclick="history.back();">back</div>

[go] ボタンをクリックして、(1)→(2)→(3) と進んでください。そして、(3) で [back] ボタンをクリックしてください。

左側は、(2)→(3) は location.assign('a3.htm'); を実行しているので、(2) の URL が履歴に残り、(3) で history.back(); したときには、(2) に戻ります。

右側は、(2)→(3) は location.replace('a3.htm'); を実行しているので、(2) の URL の履歴が (3) の URL で上書きされてしまい、(3) で history.back(); したときには、(1) に戻ることになります。

なお、もう一度実行したいときには、[最初から] ボタンをクリックしてください。

実行例
最初から

8.4.3  再読み込み

location.reload()

現在のページを再読み込みする

引数 なし

戻り値:なし

記述例
  <div class="switch" onclick="location.reload();">リロード</div>
  <span>リロード時刻:</span><span id="t"></span>
     
  <script>
  let d = new Date();
  document.getElementById("t").textContent = d.toLocaleString();   // 受信日時
  </script>

[リロード] ボタンをクリックすると、ドキュメントが再読み込みされ読み込まれた日時が表示されます。

実行例

8.5   スタイルシート(Stylesheet)

ドキュメントで使用されるスタイルシートは、document の styleSheets プロパティで一元的に保持されており、次のような構造をしています。また、各要素で個別に指定されたスタイル属性は、要素の style 属性で参照することができます。

html
document
CSSStylesheet[] styleSheets
CSSStyleRule[] cssRules
CSSStyleDeclaration style
 :
 :
 :
element
CSSStyleDeclaration[] style

 :
element
CSSStyleDeclaration[] style

 :


CSSStylesheet[] styleSheets

link 要素や style 要素で指定されたスタイルシートごとに、リストに保存されます。

  <link rel="stylesheet" href="xxxxx.css">
  <style> …… </style>
CSSStyleRule[] cssRules

スタイルシート内の セレクタ {プロパティ:値; …… } ごとに、リストに保存されます。

  <style>
    strong {color:red;font-weight:bold;}
    div.note {background-color:yellow;}
  </style>
CSSStyleDeclaration[] style

プロパティ:値; ごとに、リストに保存されます。

  <style>
    strong {
      color:red;
      background-color:lightgrey;
      font-weight:bold;
    }
  </style>
  
<div style="color:red;font-weight:bold;">文字列</div>

8.5.1  スタイルシート (CSSStyleSheet)

document の styleSheets プロパティで CSSStyleSheet のリストが得られます。

CSSStyleSheet のリストは link 要素も含め記述した順に作成されます。


CSSStyleSheet オブジェクトの主なプロパティとメソッドについて説明します。

(1) スタイルシート情報

プロパティ
cssRulesCSSStyleRule(セレクタ要素)のリスト(CSSRuleList)を返す。
セレクタ {プロパティ:値;}
hrefR/Olink 要素の href 属性値(style 要素のときは "")を返す。
記述例
h3080501(1)a.css
p { color: red; } 
span {font-weight: bold;}
<html>
 <head>
  <meta charset="UTF-8">
  <title>styleSheets</title>
  <link rel="stylesheet" href="h3080501(1)a.css">    <!-- 一つ目のスタイルシート -->
  <style>                                            <!-- 二つ目のスタイルシート -->
    td { font-size: 9pt; vertical-align: top;}
    .note {
      font-size: 9pt;
      color: chocolate;
    }
  </style>
 </head>
 <body>
  <table>
   <tr><td id="d00"></td><td></td><td id="d01"></td></tr>
   <tr><td id="d10"></td><td></td><td id="d11"></td></tr>
  </table>
  <script>
  for (let x = 0 ; x < document.styleSheets.length ; x++) {
    let ss = document.styleSheets[x];                       // ss : CSSStyleSheet
    document.getElementById("d" + x + "0").textContent = ss.href;
    let rules = "";
    for (let n = 0 ; n < ss.cssRules.length ; n++) {
      rules += n + ":" + ss.cssRules[n].cssText + "<br>";
    }
    document.getElementById("d" + x + "1").innerHTML = rules;
  }
  </script>
 </body>
</html>

一つ目は link 要素で記述されたスタイルシートなので、href が設定されています。二つ目は style 要素で記述されているため href はありません。

実行例

(2) スタイルシートの追加・削除

スタイルシート.insertRule(rule, index)

ルールを指定位置に挿入する。

引数 rule:ルール(セレクタ {プロパティ:値;})

引数 index:挿入する番号(0~)

戻り値:なし


スタイルシート.deleteRule(index)

スタイルルールを除去する。

引数 index:削除するルールの番号

戻り値:なし

記述例
<html>
 <head>
  <meta charset="UTF-8">
  <title>styleSheets</title>
  <style>
    p { color: red; } 
    span {font-weight: bold;}
    .note {
      font-size: 9pt;
      color: chocolate;
    }
  </style>
 </head>
 <body>
  <div id="d1"></div>
  <div id="d2"></div>
  <div id="d3"></div>
  <script>
  function dispStyle(style) {      // style : CSSStyleDeclaration
    let s = "";
    for (let i = 0 ; i < style.length ; i++) {
      let n = style[i];
      s += n + ": " + style[n] + "; ";
    }
    return s;
  }
  function dispRules(rules) {      // rules : CSSStyleRule 
    let s = "";
    for (let i = 0 ; i < rules.length ; i++) {
      s += rules[i].selectorText + " {" + dispStyle(rules[i].style) + "} ";
    }
    return s;
  }
  let ss = document.styleSheets[0];                       // ss : CSSStyleSheet
  document.getElementById("d1").textContent= dispRules(ss.cssRules);
  ss.deleteRule(1);                                                  // 二つ目のスタイルルールを削除
  document.getElementById("d2").textContent= dispRules(ss.cssRules);
  ss.insertRule("span {font-style: italic;}", ss.cssRules.length);   // 最後に新たなスタイルルールを追加
  document.getElementById("d3").textContent= dispRules(ss.cssRules);
  </script>
 </body>
</html>

二つ目のスタイルルール(span {font-weight: bold;})を削除した後、別のルール(span {font-style: italic;})を最後に挿入しています

実行例

8.5.2  ルール (CSSStyleRule)

document の styleSheets プロパティで得られた CSSStyleSheet の cssRules で CSSStyleRule のリストである CSSRuleList が得られます。CSSStyleRule はそのリストの要素です。

プロパティ
cssTextR/Oスタイルルールの実際のテキスト
selectorTextR/Oルールセットのセレクタ文字列
styleR/Oスタイルシートの定義 CSSStyleDeclaration のリスト
記述例
<html>
 <head>
  <meta charset="UTF-8">
  <title>CSSStyleRule</title>
  <style>
    p { color: red; } 
    span {font-weight: bold;}
    td { font-size: 9pt; vertical-align: top; }
    .note {
      font-size: 9pt;
      color: chocolate;
    }
  </style>
 </head>
 <body>
  <table>
   <tr><td id="d10"></td><td id="d20"></td><td id="d30"></td></tr>
   <!-- 以下略 -->
  </table>

  <script>
  let rules = document.styleSheets[0].cssRules;       // rules : CSSRuleList
  for (let i = 0 ; i < rules.length ; i++) {
    let rule = rules[i];                              // rule : CSSStyleRule
    document.getElementById("d1" + i).textContent = rule.cssText;
    document.getElementById("d2" + i).textContent = rule.selectorText;
    document.getElementById("d3" + i).textContent = rule.style;
  }
  </script>
 </body>
</html>

スタイルシートで定義されているルールのセレクタとその定義を表示しています。

実行例

8.5.3  スタイル属性 (CSSStyleDeclaration)

document の styleSheets プロパティで得られた CSSStyleSheet の cssRules で得られた CSSStyleRule の style で得られます。

また、エレメントの style 属性でも得られます。

プロパティ
cssTextR/Oスタイルシート定義文字列(スタイルシート属性名と属性値のペアからなる文字列)
parentRuleこのスタイル属性を持つルール CSSStyleRule(要素のスタイルシートの場合は null)
記述例
<html>
 <head>
  <meta charset="UTF-8">
  <title>CSSStyleDeclaration</title>
  <style>
    td { font-size: 9pt; vertical-align: top; }
    .note {
      font-size: 9pt;
      color: chocolate;
    }
  </style>
 </head>
 <body>
  <div id="t" style="background-color:yellow;" ></div>
  <table>
   <tr><td id="d10"></td><td id="d20"></td><td id="d30"></td></tr>
   <!-- 以下略 -->
  </table>

  <script>
  // <style>
  let rules = document.styleSheets[0].cssRules;  // CSSRuleList
  let i = 0;
  for ( ; i < rules.length; i++) {
    let sd = rules[i].style;     // CSSStyleDeclaration
    document.getElementById("d1" + i).textContent = sd.cssText;
    document.getElementById("d2" + i).textContent = sd.parentRule;  // CSSStyleRule
    document.getElementById("d3" + i).innerHTML = getStyleString(sd);
  }
  // <div id="t" style="background-color:yellow;>"
  let sd = document.getElementById("t").style;          // CSSStyleDeclaration
  document.getElementById("d1" + i).textContent = sd.cssText;
  document.getElementById("d2" + i).textContent = sd.parentRule;  // CSSStyleRule
  document.getElementById("d3" + i).innerHTML = getStyleString(sd);
  
  function getStyleString(styles) {
    let styleString = "";
    for (let n = 0 ; n < styles.length ; n++) {
      let style = styles[n];
      styleString += style + ":" + styles[style] + "<br>";
    }
    return styleString;
  }
  </script>
 </body>
</html>

一つ目は link 要素や style 要素で指定されたスタイルシートを、二つ目は id="t" の div 要素に個別に指定された style 属性値を表示しています。

実行例



また、style 属性値を変更することで、要素のスタイルを変更することができます。要素に style 属性が記述されていなくても構いません。

ただし、このとき指定する属性名はスタイルシートで指定した名前とは少し異なります。スタイルシートで指定する名前は、font-size や background-color のように "-" を含むものもありますが、Javascript では "-" は減算演算子と見なされてしまいます。したがって、"-" は使用できませんので、Javascript では "-" を省き "-" の次に位置している文字を大文字にして使用します。例えば、fontSize や backgroundColor です。

記述例
<html>
 <head>
  <meta charset="UTF-8">
  <title>styleSheets</title>
  <style>
    .x { background-color:white; }
  </style>
 </head>
 <body>
  <table>
   <tr><th>エレメントの style 変更</th><th>sytle 要素の style 変更</th><th style="width:30em;"></th></tr>
   <tr><td id="t1">スタイルシート指定なし</td><td class="x">class 指定</td></tr>
   <tr><td id="t2" class="x">class 指定</td><td  class="x">class 指定</td></tr>
   <tr><td id="t3" style="background-color:white;">style 属性指定</td><td class="x">class 指定</td></tr>
  <table>
  <script>
  document.getElementById("t1").style.backgroundColor = "yellow";    // 背景色 yellow
  document.getElementById("t2").style.backgroundColor = "yellow";
  document.getElementById("t3").style.backgroundColor = "yellow";
  
  let ss = document.styleSheets[0].cssRules[0].style;           // .x のスタイル属性
  ss.backgroundColor = "lime";           // 背景色 lime
  ss.color = "blue";                     // 文字色 blue
  </script>
 </body>
</html>

どのような方法でスタイルシートが指定されていても(あるいはまったく指定されていなくても)エレメントの style 属性値は、同じように変更することができます。

また、sytle 要素の style を変更して、そのルールを class で指定したエレメントすべてを一度に変更することもできます。ただし、id="t2" のエレメントのように元は class で指定していても、後で個別に変更してしまったスタイル属性は個別の変更が優先されるようです。

実行例

8.6   イベント(Event)

イベントオブジェクトは、イベントが起きたときに呼び出されるメソッド(イベントリスナー)に最初の引数として渡されます。もし参照の必要がなければ、引数を記述しなくても構いません。

function foo(event) {
  // event引数はイベントオブジェクトを自動的に割り当てられます
  alert(event);
}
button.onclick = foo;

イベントの発生によって実行されるイベントハンドラーに、引数として渡されるイベントオブジェクトは、 Event から派生しているか、あるいは Event から派生したイベントオブジェクトから派生しています。



イベントについては、「10 イベント」を参照してください。

8.7   ノード(Node)

Document や Element は Node を継承しています。よって、それらは次に挙げる Node のメソッドやプロパティも持っていることになります。

8.7.1  ノード情報

ノードが持つ主なプロパティです。

プロパティ
nodeNameR/Oノード名
nodeTypeR/Oノードの種類
名称
ELEMENT_NODE1
ATTRIBUTE_NODE2
TEXT_NODE3
CDATA_SECTION_NODE4
PROCESSING_INSTRUCTION_NODE7
COMMENT_NODE8
DOCUMENT_NODE9
DOCUMENT_TYPE_NODE10
DOCUMENT_FRAGMENT_NODE11
nodeValueノードの値
parentNodeR/O親ノード
parentElementR/O親ノードの Element オブジェクト
textContentそのノードおよびすべての子孫の全テキスト内容
childNodesR/O子ノードリスト
firstChildR/O最初の子ノード、なければ null
lastChildR/O最後の子ノード、なければ null
nextSiblingR/Oひとつ次の兄弟ノード、なければ null
previousSiblingR/Oひとつ前の兄弟ノード、なければ null
記述例
<html>
 <head>
  <title>タイトル</title>
  <meta name="author" content="KOJIMA Takashi">
  <meta charset="UTF-8">
  <script>
  function dispNode(node, ind) {
   let s = ind + node.nodeName + "(" + node.nodeType + ")"
                + (node.nodeType != 1 && node.nodeType < 9 ? node.textContent : "");
   for (let i = 0 ; i < node.childNodes.length ; i++) {
    s += dispNode(node.childNodes[i], ind + " ");
   }
   return s;
  }
  </script>
 </head>
 <body onload="document.getElementById('d').textContent=dispNode(document, '');">
  <h1>見出し</h1>
  <!-- コメント -->
  <p><strong>強調強調</strong>本文本文 ... 本文</p>
  <p>本文本文 ... 本文</p>
  <pre id="d" style="border:solid 1px gray"></pre>
 </body>
</html>

HTML の内容を下側の枠の中に表示しています。エレメントの場合は ノード名(ノードタイプ)ローカル名、その他は ノード名(ノードタイプ)テキスト内容 を表示しています。なお、#text(3) のみの行は改行だと思われます。

実行例

8.7.2  ノードの追加・置換・削除

親要素へノードの追加、削除、置換、挿入をします。

-->

ノード.appendChild(child)

ノードの最後に指定されたノード(child)を子要素として追加する。

引数 child:追加するノード

戻り値:追加したノード


ノード.removeChild(child)

ノードから指定されたノード(child)を取り除く。

引数 child:削除するノード

戻り値:取り除いたノード


ノード.replaceChild(newChild, oldChild)

ノードから元のノード(oldChild)を取り除き新しいノード(newChild)と置き換える。

引数 newChild:新しいノード

引数 oldChild:元のノード

戻り値:元のノード


ノード.insertBefore(newChild, refChild)

ノードの子要素である参照ノード(refChild)の前に(参照ノードが null の場合は末尾に)新しいノード(newChild)を挿入する。

引数 newChild:新しいノード

引数 refChild:参照ノード

戻り値:挿入したノード

記述例
<p id="p1">replacing node</p>
<p id="p2">removing node</p>
<div id="initSwitch" class="switch" onClick="location.reload(false);" title="初期状態">初期状態</div> 
<div id="appendSwitch" class="switch" onClick="append();" title="追加">追加</div> 
<div id="insertSwitch" class="switch" onClick="insert();" title="挿入">挿入</div> 
<div id="modifySwitch" class="switch" onClick="modify();" title="変更">変更</div> 
<div id="removeSwitch" class="switch" onClick="remove();" title="削除">削除</div>
<script>
function append() {
  let p = document.createElement("p");
  p.textContent="appended node";
  p.style.color="red";
  document.body.appendChild(p);         // body の最後に追加する
}
function insert() {
  let p = document.createElement("p");
  p.textContent="inserted node";
  p.style.color="red";
  let sw = document.getElementById("initSwitch");
  document.body.insertBefore(p, sw);    // sw の前に追加する
}
function modify() {
  let p1 = document.getElementById("p1");
  let p = document.createElement("p");
  p.textContent="replaced node";
  p.style.color="red";
  document.body.replaceChild(p, p1);    // p1 を p で置き換える
}
function remove() {
  let p2 = document.getElementById("p2");
  document.body.removeChild(p2);        // p2 を削除する
}
</script>

ボタンをクリックすると、親要素である body のノードが追加、挿入、変更、削除されます。

なお、記述例では省略してありますが、同じボタンはクリックできないようにしてあります。

実行例

ノードを途中に挿入するためには、insertBefore しかありません。しかし、このメソッドは指定したノードの前に挿入します。

ノードの後ろに挿入するためには、nextSibling を使用し次のノードを得て、その前に挿入するようにします。

記述例
<div>----------</div>
<div id="target">Target</div>
<div>----------</div>
<script>
let div1 = document.createElement("div");
div1.textContent="before";
div1.style.color="blue";
document.body.insertBefore(div1, target);
let div2 = document.createElement("div");
div2.textContent="after";
div2.style.color="red";
document.body.insertBefore(div2, target.nextSibling);    // 次のノードの前に挿入
</script>
実行例

8.7.3  ノードのチェック

ノードが存在するかどうかなどのチェックをします。

ノード.hasChildNodes()

子ノードを持つかどうかを返す。

戻り値:あり(true)、なし(false)


ノード.contains(child)

特定の子ノードを持つかどうかを返す。

引数 child:調べたいノード

戻り値:あり(true)、なし(false)


ノード.isEqualNode(Child)

指定のノードと等しいかどうかを返す。

引数 child:比較ノード

戻り値:等しい(true)、等しくない(false)

記述例
<table id="tb" style="display:none;">
 <tr><td>r1c1</td><td id="current">r1c2</td><td>r1c3</td></tr>
 <tr><td>r1c1</td><td>r1c2</td><td>r1c3</td></tr>
</table>
<div id="d1"></div>
<!-- 以下略 -->

<script>
  let t = document.getElementById("tb");
  document.getElementById("d1").textContent = t.hasChildNodes();
  let c = document.getElementById("current");
  document.getElementById("d2").textContent = t.contains(c);
  let r = t.getElementsByTagName("tr")[0];    // 最初の tr タグ
  document.getElementById("d3").textContent = r.childNodes[1].isEqualNode(c);
</script>
実行例

8.7.4  ノードのコピー

ノードをコピーします。ノードなどのオブジェクトは、単なる代入ではそのオブジェクトへの参照がコピー(シャローコピー)されるだけで、実体はコピーされません。したがって、代入の結果、コピー元とコピー先は同じオブジェクトを参照することになります。

cloneNode はノードの複製(ディープコピー)を返します。また、引数で true を指定した場合は子孫を含めた完全な複製を作成します。

ノード.cloneNode(deep)

ノードの複製を返す。

引数 deep:子孫ノードも含めてコピーするかどうか

戻り値:子孫ノードもコピーする(true)、コピーしない(false)規定値

戻り値:ノードの複製

appendChild は、document 上に存在するノードだと位置が移動するだけのようです。したがって、単に代入しただけの a0 はコピー元からコピー先(d0)に移動しています。

それに対して、cloneNode して複製を作成した a1 と a2 はコピー元が残ったままコピー先(d1 や d2)に複製されています。ただし、a1 はテキストを含めた子孫は複製していないので、テキストはコピーされていません。しかし、それだと何も分からないので、コピー元にスタイルシートで枠を描いています。枠はコピーされています。

記述例
<table>
 <tr><td>コピー先</td><td>     </td><td>コピー元</td></tr>
 <tr><td id="d0"></td><td> ← </td><td><span style="color:red;">AAAAA</span></td></tr>
 <tr><td id="d1"></td><td> ← </td><td><span style="color:blue;double 3px gray;">BBBBB</span></td></tr>
 <tr><td id="d2"></td><td> ← </td><td><span style="color:green;">CCCCC</span></td></tr>
</table>

<script>
let a = document.querySelectorAll("span");
let a0 = a[0];                      // 単なる代入(参照がコピーされるだけで、a0 も a[0] も実体は同じもの)
let a1 = a[1].cloneNode(false);     // ディープコピー(子孫は複製されない)
let a2 = a[2].cloneNode(true);      // ディープコピー(子孫を含めてすべて複製される)
document.getElementById("d0").appendChild(a0);
document.getElementById("d1").appendChild(a1);
document.getElementById("d2").appendChild(a2);
</script>
実行例

ただし、イベントハンドラは属性として記述されたもの(インラインイベントハンドラ)はコピーされます(一番目の例)が、Javascript で代入されたもの(二番目の例)や addEventListener で設定されたもの(三番目の例)はコピーされません。

文字列にマウスポインタを重ねてください。イベントハンドラが記述されているものは背景色が黄色くなります。

記述例
<table>
 <tr><td>コピー先</td><td>     </td><td>コピー元</td></tr>
 <tr><td id="d0"></td><td> ← </td><td><span id="a" onmouseenter="this.style.backgroundColor='yellow';" onmouseleave="this.style.backgroundColor='transparent';">AAAAA</span></td></tr>
 <tr><td id="d1"></td><td> ← </td><td><span id="b">BBBBB</span></td></tr>
 <tr><td id="d2"></td><td> ← </td><td><span id="c">CCCCC</span></td></tr>
</table>

<script>
let a = document.getElementById("a");
let b = document.getElementById("b");
let c = document.getElementById("c");
b.onmouseenter = function() {this.style.backgroundColor='yellow';}
b.onmouseleave = function() {this.style.backgroundColor='transparent';}
c.addEventListener("mouseenter", function() {this.style.backgroundColor='yellow';}, false);
c.addEventListener("mouseleave", function() {this.style.backgroundColor='transparent';}, false);
document.getElementById("d0").appendChild(a.cloneNode(true));  // onmouseenter 属性
document.getElementById("d1").appendChild(b.cloneNode(true));  // onmouseenter 代入
document.getElementById("d2").appendChild(c.cloneNode(true));  // addEventListener
</script>
実行例

8.8   ドキュメント(Document)

document オブジェクトは表示している文書自体を示します。

なお、Document は Node を継承していますので、Node のプロパティや機能を使用することができます。

Node Document

document オブジェクトの主なプロパティとメソッドについて説明します。

8.8.1  ドキュメント情報

(1) ドキュメント情報

プロパティ
URLR/O文書のロケーション
locationR/O現在の document の URI
characterSetR/O適用されている文字セット(エンコーディング)
doctypeR/O文書型宣言 (DTD)
lastModifiedR/O最終更新日
title文書のタイトル

記述例
<!DOCTYPE html>
<html>
  <head>
    <title>Sample Document</title>
    <meta charset="UTF-8">
  </head>
  <body>
    <div id="d1"></div>
    <!-- 以下略 -->
    <script>
      document.getElementById('d1').textContent=document.URL;
      document.getElementById('d2').textContent=document.location;
      document.getElementById('d3').textContent=document.characterSet;
      document.getElementById('d4').textContent=document.doctype.name;
      document.getElementById('d5').textContent=document.lastModified;
      document.getElementById('d6').textContent=document.title;
    </script>
  </body>
</html>
実行例

(2) HTML情報

プロパティ
headR/Ohead 要素のリスト
styleSheetsR/Oすべての stylesheet 要素のリスト
scriptsR/Oすべての script 要素のリスト
bodybody 要素
formsR/Oform 要素のリスト
linksR/Oすべてのハイパーリンクのリスト
imagesR/O画像のリスト

記述例
<!DOCTYPE html>
<html>
  <head>
    <title>タイトル</title>
    <style>
      <!-- スタイルシート -->
    </style>
    <script>
      <!-- スクリプト -->
    </script>
  </head>
  <body>
    <form name="f1"></form>
    <a href="another.htm">aaa</a>
    <img src="figures/bear.png">
    <div id="d1"></div>
    <!-- 以下略 -->
    <script>
      <!-- スクリプト -->
      document.getElementById('d1').textContent=document.head.nodeName;
      document.getElementById('d2').textContent=document.styleSheets.length;
      document.getElementById('d4').textContent=document.scripts.length;
      document.getElementById('d4').textContent=document.body.nodeName;
      document.getElementById('d5').textContent=document.forms[0].name;
      document.getElementById('d6').textContent=document.links[0].href;
      document.getElementById('d7').textContent=document.images[0].src;
    </script>
  </body>
</html>

forms、links、images は最初の要素を表示しています。

実行例

8.8.2  ドキュメント出力

(1) open

ドキュメント.open()

ドキュメントを開いて書込み可能にする。

戻り値:なし


記述例
  document.open();

(2) close

ドキュメント.close()

ドキュメントへの書き込みを閉じる。

戻り値:なし


記述例
  document.open();

  document.close();

(3)write、writeln

ドキュメント.write(string)

ドキュメントに文字列を出力する。

引数 string:出力文字列

戻り値:なし


document.writeln(string)

ドキュメントに文字列と改行文字を出力する。

ただし、改行要素 <br> ではないため、表示上は改行されない。

引数 string:出力文字列

戻り値:なし


記述例
  document.open();
  document.write("今は、");
  let t = new Date();
  document.writeln(t.toLocaleTimeString() + "です。");
  document.close();

実行例

8.8.3  ドキュメント要素

(1) getElementById、getElementsByName、getElementsByClassName、getElementsByTagName、getElementsByTagNameNS

id や name、class などの属性、あるいは 要素名をドキュメント内から検索し、見つかった要素を取得することができます。なお、見つからない場合には、null 値となります。

ドキュメント.getElementById(id)

特定の id 属性値を持つ要素を得る。同じ id を持つ要素が複数あった場合には最初の要素を得る。

引数 id:id 属性値

戻り値:要素(Element)


ドキュメント.getElementsByName(name)

特定の name 属性値を持つ要素を得る。

引数 name:name 属性値

戻り値:要素(Element)のリスト


ドキュメント.getElementsByClassName(class)

特定の(スタイルシートの) class 属性値を持つ要素を得る。

引数 class:class 属性値

戻り値:要素(Element)のリスト


ドキュメント.getElementsByTagName(tag)

特定のタグの要素を得る。

引数 tag:タグ名

戻り値:要素(Element)のリスト


記述例
<div id="sw1" class="switch">スイッチ1</div> <div id="sw2" class="switch x">スイッチ2</div>
<form action="#">
  <input type="radio" name="option" value="1">選択1
  <input type="radio" name="option" value="2">選択2
  <input type="radio" name="option" value="3" checked>選択3
</form>
<div id="d1"></div>
<!-- 以下略 -->

<script>
  document.getElementById('d1').textContent=document.getElementById("sw1").textContent;
  document.getElementById('d2').textContent=document.getElementsByName("option")[0].checked;
  document.getElementById('d3').textContent=document.getElementsByTagName("input")[2].checked;
  document.getElementById('d4').textContent=document.getElementsByClassName("switch x")[0].textContent;
</script>
実行例

なお、たいていのブラウザでは、次のように id を変数のように使用して getElementById と同様に id の要素を得ることもできます。

記述例
<div id="x">x の内容</div>
<div id="d1"></div>
<div id="d2"></div>

<script>
  document.getElementById('d1').textContent = document.getElementById('x').textContent;
  document.getElementById('d2').textContent = x.textContent;   // id である x を変数のように使用する
</script>
実行例


名前空間を指定する場合は次のメソッドを使用します。

ドキュメント.getElementsByTagNameNS(namespace, tag)

指定された名前空間内の特定のタグの要素を得る。

引数 namespace:名前空間URI(例えば、HTML は http://www.w3.org/1999/xhtml、SVG は http://www.w3.org/2000/svg)

引数 tag:タグ名、*(すべて)

戻り値:要素(Element)のリスト

記述例
<ol id="ol" style="display:inline-block;">
  <li id="li1">aaaaa</li>
  <li id="li2">bbbbb</li>
  <li id="li3">ccccc</li>
</ol>
<svg id="svg" viewbox="0,0 250 90" width="250" height="90">
  <image id="image1" x="50" y="10" width="74" height="74" xlink:href="bear.png"/>
  <image id="image2" x="130" y="10" width="74" height="74" xlink:href="bear2.png"/>
</svg>

<div id="d11"></div><div id="d12"></div>

<script>
  document.getElementById('d11').textContent=document.getElementsByTagNameNS(
                                               "http://www.w3.org/1999/xhtml", "li")[1].id;
  document.getElementById('d12').textContent=document.getElementsByTagNameNS(
                                               "http://www.w3.org/2000/svg", "image")[1].id;
</script>
実行例

(2) createElement、createElementNS

ドキュメント.createElement(tag[, options])

指定されたタグ要素を新たに作成する。

引数 tag:タグ名

引数 options:{ is : 'カスタム要素のタグ名' }     カスタム要素を参照してください)

戻り値:要素(Element)


記述例
<form name="F1" action="#">
<select name="S1" size="3">
<option>AAA
<option>BBB
</select>
</form>

<script>
  let elm = document.createElement("option");
  elm.text = "CCC";
  document.F1.S1.add(elm);
</script>

実行例

SVG 要素などの作成には名前空間を指定する必要があるので、次のメソッドを使用します。

ドキュメント.createElementNS(namespace, tag)

指定された名前空間にタグ要素を新たに作成する。

引数 namespace:名前空間URI(例えば、SVGは http://www.w3.org/2000/svg)

引数 tag:タグ名

戻り値:要素(Element)


記述例
<svg id="svg" viewbox="0,0 50 50" width="50" height="50"></svg>

<script>
  let circle = document.createElementNS("http://www.w3.org/2000/svg", "circle");
  circle.setAttribute("cx", 30);
  circle.setAttribute("cy", 30);
  circle.setAttribute("r", 20);
  circle.setAttribute("fill", "green");
  document.getElementById("svg").appendChild(circle);
</script>

実行例

(3) createTextNode

ドキュメント.createTextNode(text)

文字列を新たに作成する。

引数 text:文字列

戻り値:テキストノード


記述例
<p id="p1"></p>

<script>
  let textnode = document.createTextNode("<div>foo</div>");
  document.getElementById("p1").appendChild(textnode);
</script>

実行例

(4) querySelector、querySelectorAll

引数で指定したセレクタ(id や name、class などの属性、あるいは 要素名などのスタイルシートを適用する対象)や結合子と一致する要素をドキュメント内から検索し、見つかった要素を取得することができます。また、見つからない場合には、null 値となります。

なお、単純な検索ならば getElementById などを使用した方が速いようです。

ドキュメント.querySelector(セレクタ)

セレクタに一致する最初の要素を得る。

引数 セレクタ:スタイルシートで指定するセレクタ(と結合子)と同じ (ただし、"," 区切りで複数指定した場合はいずれかと一致するという意味になる)

戻り値:要素(Element)

ドキュメント.querySelectorAll(セレクタ)

セレクタに一致する要素をすべて得る。

引数 セレクタ:スタイルシートで指定するセレクタ(と結合子)と同じ (ただし、"," 区切りで複数指定した場合はいずれかと一致するという意味になる)

戻り値:要素(Element)のリスト


記述例
<div id="sw1" class="switch">スイッチ1</div> <div id="sw2" class="switch x">スイッチ2</div>
<form action="#">
  <input type="radio" name="option" value="1">選択1
  <input type="radio" name="option" value="2">選択2
  <input type="radio" name="option" value="3" checked>選択3
</form>
<div id="d1"></div>
<!-- 以下略 -->

<script>
  document.getElementById('d1').textContent=document.querySelector("#sw1").textContent;
  document.getElementById('d2').textContent=document.querySelector("input").checked;              // 選択1
  document.getElementById('d3').textContent=document.querySelectorAll("input")[2].checked;        // 選択3
  document.getElementById('d4').textContent=document.querySelector(".switch, .x").textContent;
</script>

4つ目の ".switch, .x" では、クラス名が "switch" または "x" に一致する最初の要素である "スイッチ1" が得られます(switch と x の AND 条件ではありません)。

実行例

なお、(1)の getElementsByName などと (4)の querySelector などは、ほとんど同じように使用することができますが、一つ大きな違いがあります。それは、getElementsByName、getElementsByTagName、getElementsByClassName で得られた要素のリストは、それらの要素に追加・削除があった場合はリストの内容も作り変えられますが、querySelector、querySelectorAll で得られた要素のリストは作り変えられないということです。

ただし、要素の内容の変更はどちらも反映されます。

記述例
<span id="e1">11111</span> <span id="e2">22222</span><br>
<span id="d11"></span> <span id="d12"></span>
<span id="d21"></span> <span id="d22"></span>

<script>
  let g = document.getElementsByTagName("span");
  let q = document.querySelectorAll("span");
  let e1 = document.getElementById("e1");
  document.body.removeChild(e1);                                  // e1 を削除
  document.getElementById('d11').textContent = g[0].textContent;
  document.getElementById('d21').textContent = q[0].textContent;
  
  document.getElementById('e2').textContent = "00000";        // e2 の内容を変更
  document.getElementById('d12').textContent = g[0].textContent;    // g[0] が 元の e2 の内容
  document.getElementById('d22').textContent = q[1].textContent;    // q[1] が 元の e2 の内容
</script>

e1 を削除して、e2 の内容を "00000" に変更しています。

その結果、getElementsByTagName で取得した g 内の最初の要素も削除され2番目の "22222" が最初の要素になっています。それに対して、querySelectorAll で取得した q は変更されず "11111" が最初の要素になっています。

ただし、要素の内容の変更は反映されるようで、e2 の内容はともに "00000" となっています。

実行例

8.8.4  フォーカス

(1) hasFocus

文書または文書内の何れかの要素がフォーカスを持っているかどうかを示します。

ドキュメント.hasFocus()

文書または文書内の何れかの要素がフォーカスを持っているかどうかを示す。

引数 なし

戻り値:文書内のアクティブ要素にフォーカスがある(true)、ない(false)


下の例は iframe 要素の中に HTML文書があるので、最初はフォーカスを持っていませんので false と表示されます。

枠の中をクリックしてみてください。フォーカスを得て true と表示されます。

枠の外か他のウィンドウをクリックすると、フォーカスが移り false と表示されます。

記述例
<span id="d1"></span><br>
<script>
setInterval(function() {
  document.getElementById("d1").textContent = document.hasFocus();
}, 1000);
</script>
実行例

8.8.5  イベント

(1) createEvent

指定されたタイプの イベント を作成します。返されるオブジェクトは初めに初期化する必要があり、その後で dispatchEvent へ渡すことができます。

ただし、初期化するための初期化メソッドのいくつかは廃止予定となっています。また、Internet Explorer 以外の多くのブラウザは、イベントオブジェクトの生成に new Eventnew MouseEvent などが用意されているので、createEvent は使用しない方が良いでしょう。

ドキュメント.createEvent(type)

特定の id 属性値を持つ要素を得る。

引数 type:id イベントタイプ

イベントタイプイベントモジュール初期化メソッド
"UIEvents"ユーザインタフェースイベントモジュールevent.initUIEvent(注1)
"MouseEvents"マウスイベントモジュールevent.initMouseEvent(注1)
"MutationEvents"(注2)変異イベントモジュールevent.initMutationEvent
"HTMLEvents"HTML イベントモジュールevent.initEvent(注1)
注1)廃止予定となっているので使用しない方が良い
注2)MutationEvent 自体が廃止予定となっているので使用しない方が良い

戻り値:イベント(Event)


click イベントを生成し、セレクト、チェックボックス、ボタンに送っています。click イベントを受け取った要素は直接クリックされたのと同じように動作します。

ちなみに、セレクトはクリックされるとランダムに項目を選択します。

記述例
<select id="select"><option>aaa<option>bbb<option>ccc</select>  <div ="sw1" class="switch" onclick="fire();">クリック</div>
<input id="check" type="checkbox"><br>
<button id="button" style="width:5em;">今の日時</button> <span id="date"></span>

<script>
  document.getElementById("select").addEventListener("click", function(){ this.selectedIndex=parseInt(Math.random() * 3); });
  document.getElementById("button").addEventListener("click", dispDate);

  function dispDate(event) {
    let d = new Date(event.timeStamp);
    document.getElementById("date").textContent=d.toLocaleString();
  }

  function fire() {
    let evt = document.createEvent("HTMLEvents");   // Event オブジェクトの生成
    evt.initEvent("click", true, true);             // 初期化(click イベント)
    document.getElementById("select").dispatchEvent(evt);   // click イベントを送る
    document.getElementById("check").dispatchEvent(evt);
    document.getElementById("button").dispatchEvent(evt);
  }
</script>

「クリック」ボタンをクリックしてみてください。セレクト、チェックボックス、ボタンの状態が変わります。

実行例

デフォルトの機能が実行されない(?)ようでチェックボックスが変化しません(ただし、Event オブジェクトを new MouseEvent() などで生成すれば変化します)。

また、timeStamp は正しく設定されません。


8.9   エレメント(Element)

Element オブジェクトは Document の一部分を表現します。

なお、Element は Node を継承していますので、Node のプロパティや機能を使用することができます。

Node Element

Element オブジェクトの主なプロパティとメソッドについて説明します。

8.9.1  エレメント情報

(1) エレメント情報

プロパティ
attributesR/Oすべての属性のリスト
childElementCount子要素の数
children子要素
classNameclass(スタイルシート)属性値
classListR/Oclass 属性のリスト
firstElementChildR/O最初の子要素
idid
innerHTML子孫のすべての要素内容(HTML を含む)
lastElementChildR/O最後の子要素
localNameR/Oノードの修飾名のコロン(:)の後ろの部分
outerHTML自身と子孫のすべての要素内容(HTML を含む)
tagNameR/O要素のタグ名

記述例
<div id="id1" class="c1 c2 c3" style="display:none;"><SPAN STYLE='COLOR:RED;'>XXX</SPAN>YYY</div>
<div id="d1"></div>
<div id="d2"></div>
<!-- 以下略 -->

<script>
  function dispList(list) {
    let s = "";
    for (let i = 0 ; i < list.length ; i++)
      s += list[i] + " ";
    return s;
  }
  function dispAttr(attr) {
    let s = "";
    for (let i = 0 ; i < attr.length ; i++)
      s += attr[i].name + "(" + attr[i].value + ") ";
    return s;
  }
  let e = document.getElementById("id1");
  document.getElementById("d1").textContent=e.id;
  document.getElementById("d2").textContent=e.tagName;
  document.getElementById("d3").textContent=e.className;
  document.getElementById("d4").textContent=dispList(e.classList);
  document.getElementById("d5").textContent=e.innerHTML;
  document.getElementById("d6").textContent=dispAttr(e.attributes);
</script>

innerHTML はタグを含みますが、textContent は含みません。

ただし、innerHTML に含まれる要素名や属性名は小文字に、また、引用符はダブルクォテーションになりますので、注意してください。

実行例

innerHTML は、自身のコンテンツ(自身のタグを含まない内容のみ)を変更しますが、outerHTML は自身のタグも含めて変更します。

記述例
<div id="id11" style="display:none;">AAA<span id="id12">X<b>Y</b></span>BB</div>
<div id="id21" style="display:none;">AAA<span id="id22">X<b>Y</b></span>BB</div>

<span id="d11"></span>  <span id="d12"></span><br>
<span id="d21"></span>  <span id="d22"></span><br>

<script>
  let e11 = document.getElementById("id11");
  let e21 = document.getElementById("id21");
  document.getElementById("d11").textContent=e11.innerHTML;
  document.getElementById("d21").textContent=e21.innerHTML;
  
  document.getElementById("id12").innerHTML = "<i>ZZZ</i>";     // "<i>ZZZ</i>" を innerHTML に代入する
  document.getElementById("id22").outerHTML = "<i>ZZZ</i>";     // "<i>ZZZ</i>" を outerHTML に代入する
  document.getElementById("d12").textContent=e11.innerHTML;
  document.getElementById("d22").textContent=e21.innerHTML;
</script>

innerHTML は、id12 のコンテンツである X<b>Y</b> を <i>ZZZ</i> で置き換えています。

outerHTML は、id22 のタグを含めた要素そのものである <span id="id22">X<b>Y</b></span> を <i>ZZZ</i> で置き換えています。

実行例

子要素は、children に保持されています。また、その要素数は childElementCount で得られます。

記述例
<div id="id1" style="display:none;">
 <span>a1<strong>b1<em>c1</em>b2</strong>a2<mark>b3</mark>a3</span><cite>x1</cite><small>x2</small>
</div>
<div id="d1" style="white-space:pre;"></div>

<script>
  function dispList(list, ind) {
    let s = "";
    for (let i = 0 ; i < list.length ; i++) {
      s += ind + list[i].tagName + "<br>";
      if (list[i].childElementCount > 0) {
        s += dispList(list[i].children, ind + "  ");
      }
    }
    return s;
  }
  let e = document.getElementById("id1");
  document.getElementById("d1").innerHTML=dispList(e.children, "");
  document.getElementById("d2").innerHTML=e.firstElementChild.tagName;
  document.getElementById("d3").innerHTML=e.lastElementChild.tagName;
</script>

得られた子要素の tagName を表示しています。

実行例

(2) クライアント情報

プロパティ
clientHeightR/Oボーダー、スクロールバーを含まない要素全体の高さ
clientLeftR/O左ボーダー
clientTopR/O上ボーダー
clientWidthR/Oボーダー、スクロールバーを含まない要素全体の横幅

記述例
<style>
div.parent {
  background-color:lightcyan;
  width:255px;
  padding:15px 15px;
}
div.child {
  background-color:lawngreen;
  height:60px;
  width:100px;
  margin:10px 40px 20px 30px;
  border-top:solid 15px limegreen;
  border-bottom:solid 25px limegreen;
  border-left:solid 35px limegreen;
  border-right:solid 45px limegreen;
  overflow: scroll;
}
</style>

<div id="parent" class="parent"><div id="child" class="child">XXXXXXXXXX<br>YYYYYYYYYY<br>ZZZZZZZZZZ</div></div>
<div id="d1"></div>
<!-- 以下略 -->

<script>
  let c = document.getElementById("child");
  document.getElementById("d1").textContent=c.clientTop;
  document.getElementById("d2").textContent=c.clientLeft;
  document.getElementById("d3").textContent=c.clientHeight;
  document.getElementById("d4").textContent=c.clientWidth;
</script>

矢印や文字列は理解の助けになるように別途表示しています。

破線の矩形は child のマージン範囲を示すために別途表示しています。

実行例

(3) スクロール情報

プロパティ
scrollHeightR/O全体を表示するのに必要な高さ
scrollLeftR/O表示されている部分の、要素の左端からの水平方向のオフセット
scrollTopR/O表示されている部分の、要素の上端からの垂直方向のオフセット
scrollWidthR/O全体を表示するのに必要な横幅

記述例
<style>
div.scroll {
  background-color:lawngreen;
  height:50px;
  width:50px;
  overflow: scroll;
}
</style>

<div id="scroll" class="scroll">A123456789<br>BB12345678<br>CCC1234567<br>DDDD123456<br>
EEEEE12345<br>FFFFFF1234<br>GGGGGGG123<br>HHHHHHHH12<br>IIIIIIIII1</div>
<div id="d1"></div>
<!-- 以下略 -->

<script>
  let s = document.getElementById("scroll");
  document.getElementById("d1").textContent=s.scrollTop;
  document.getElementById("d2").textContent=s.scrollLeft;
  document.getElementById("d3").textContent=s.scrollHeight;
  document.getElementById("d4").textContent=s.scrollWidth;
</script>

左側の要素をスクロールさせると、スクロール情報が変化します。

右側の要素は、スクロール情報を説明するために別途表示しています。

実行例

8.9.2  エレメントの要素

(1) getElementsByClassName、getElementsByTagName、getElementsByTagNameNS

id や 要素名を特定の要素内から検索し、見つかった要素を取得することができます。なお、見つからない場合には、null 値となります。

エレメント.getElementsByClassName(class)

特定のクラス名を持つ要素を得る。

ただし、このメソッドは一般的な要素にはあるが、SVG 要素にはない。

引数 class:クラス名

戻り値:要素(Element)のリスト


エレメント.getElementsByTagName(tag)

特定のタグの要素を得る。

引数 tag:タグ名

戻り値:要素(Element)のリスト


記述例
<ol id="ol" style="display:inline-block;">
  <li id="li1">aaaaa</li>
  <li id="li2">bbbbb</li>
  <li id="li3" class="emphasis">ccccc</li>
</ol>
<svg id="svg" viewbox="0,0 150 90" width="150" height="90">
  <image id="image1" class="emphasis" x="50" y="10" width="74" height="74" xlink:href="bear.png"/>
</svg>

<div id="d11"></div><div id="d12"></div>
<!-- 以下略 -->

<script>
  let o = document.getElementById('ol');
  let s = document.getElementById('svg');
  document.getElementById('d11').textContent=o.getElementsByClassName("emphasis")[0].id;
  document.getElementById('d12').textContent=s.getElementsByClassName("emphasis")[0].id;
  
  document.getElementById('d21').textContent=o.getElementsByTagName("li")[0].id;
  document.getElementById('d22').textContent=s.getElementsByTagName("image")[0].id;
</script>

getElementById や getElementsByClassName などで取得された要素の ID を表示しています。

1つ目の例は、ol 要素の getElementById で、li2 という ID を持つ要素を得ようとしていますが、ol 要素には getElementById が無いので、例外が発生しています。しかし、通常 HTML 要素の ID はドキュメントでユニークなので、要素ごとに探す必要はなく document.getElementById を使用すれば目的の ID を持つ要素を得られます。

svg 要素には getElementById があるようなので image1 という ID を持つ要素を得ることができています。

実行例

SVG 要素内の要素の ID は SVG ごとにユニークである必要はありますが、ドキュメント全体でユニークである必要はありません(他の SVG で使用されている ID を使用しても構いません)。そのため、要素ごとに探す必要があります。

記述例
<svg id="svg1" viewbox="0,0 150 110" width="150" height="110">
  <image id="image1" x="50" y="20" width="74" height="74" xlink:href="bear.png"/>
  <circle id="circle1" cx="30" cy="40" r="20" fill="green">
</svg>
<svg id="svg2" viewbox="0,0 150 110" width="150" height="110">
  <image id="image1" x="50" y="20" width="74" height="74" xlink:href="bear2.png"/>
  <circle id="circle2" cx="30" cy="40" r="20" fill="green">
</svg>

<div id="d11"></div><div id="d12"></div>
<div id="d21"></div><div id="d22"></div>

<script>
  let s1 = document.getElementById('svg1');
  let s2 = document.getElementById('svg2');
  document.getElementById('d11').textContent=s1.getElementById("image1").tagName;
  document.getElementById('d12').textContent=s2.getElementById("image1").tagName;

  document.getElementById('d21').textContent=s1.getElementById("circle1").tagName;
  try {
    document.getElementById('d22').textContent=s2.getElementById("circle1").tagName;
  }
  catch(x) {
    document.getElementById('d22').textContent=x.message;
  }
</script>

image1 は svg1 にも svg2 にもありますが、circle1 は svg2 にはありませんので例外が発生します。

なお、色のついた文字列は説明のために別途表示しています。

実行例

名前空間を指定する場合は次のメソッドを使用します。

エレメント.getElementsByTagNameNS(namespace, tag)

指定された名前空間内の特定のタグの要素を得る。

引数 namespace:名前空間URI(例えば、HTML は http://www.w3.org/1999/xhtml、SVG は http://www.w3.org/2000/svg)

引数 tag:タグ名、*(すべて)

戻り値:要素(Element)のリスト

記述例
<ol id="ol" style="display:inline-block;">
  <li id="li1">aaaaa</li>
  <li id="li2">bbbbb</li>
  <li id="li3">ccccc</li>
</ol>
<svg id="svg" viewbox="0,0 250 90" width="250" height="90">
  <image id="image1" x="50" y="10" width="74" height="74" xlink:href="bear.png"/>
  <image id="image2" x="130" y="10" width="74" height="74" xlink:href="bear2.png"/>
</svg>

<div id="d11"></div><div id="d12"></div>

<script>
  let o = document.getElementById('ol');
  let s = document.getElementById('svg');
  document.getElementById('d11').textContent=o.getElementsByTagNameNS(
                                               "http://www.w3.org/1999/xhtml", "li")[1].id;
  document.getElementById('d12').textContent=s.getElementsByTagNameNS(
                                               "http://www.w3.org/2000/svg", "image")[1].id;
</script>
実行例

(2) 、querySelectorAll

引数で指定したセレクタ(id や name、class などの属性、あるいは 要素名などのスタイルシートを適用する対象)や結合子と一致する要素をドキュメント内から検索し、見つかった要素を取得することができます。また、見つからない場合には、null 値となります。

なお、単純な検索ならば getElementById などを使用した方が速いようです。

エレメント.querySelector(セレクタ)

セレクタに一致する最初の要素を得る。

引数 セレクタ:スタイルシートで指定するセレクタ(と結合子)と同じ (ただし、"," 区切りで複数指定した場合はいずれかと一致するという意味になる)

戻り値:要素(Element)

エレメント.querySelectorAll(セレクタ)

セレクタに一致するすべての要素を得る。

引数 セレクタ:スタイルシートで指定するセレクタ(と結合子)と同じ (ただし、"," 区切りで複数指定した場合はいずれかと一致するという意味になる)

戻り値:要素(Element)のリスト


記述例
<ol id="ol" style="display:inline-block;">
  <li id="li1">aaaaa</li>
  <li id="li2" class="emphasis">bbbbb</li>
  <li id="li3" class="emphasis x">ccccc</li>
</ol>
<div id="d1"></div>
<!-- 以下略 -->

<script>
  let ol = document.getElementById("ol");
  document.getElementById('d1').textContent=ol.querySelector("#li1").textContent;
  document.getElementById('d2').textContent=ol.querySelector("li").textContent;              // aaaaa
  document.getElementById('d3').textContent=ol.querySelectorAll("li")[2].textContent;        // ccccc
  document.getElementById('d4').textContent=ol.querySelector(".emphasis, .x").textContent;
</script>

4つ目の ".emphasis, .x" では、クラス名が "emphasis" または "x" に一致する最初の要素である "bbbbb" が得られます(emphasis と x の AND 条件ではありません)。

実行例

なお、(1)の getElementsByName などと (2)の querySelector などは、ほとんど同じように使用することができますが、一つ大きな違いがあります。それは、getElementsByName、getElementsByTagName、getElementsByClassName で得られた要素のリストは、それらの要素に追加・削除があった場合はリストの内容も作り変えられますが、querySelector、querySelectorAll で得られた要素のリストは作り変えられないということです。

ただし、要素の内容の変更はどちらも反映されます。

記述例
<ol id="ol" style="display:inline-block;">
  <li id="li1">aaaaa</li>
  <li id="li2">bbbbb</li>
  <li id="li3">ccccc</li>
</ol>
<span id="d11"></span> <span id="d12"></span>
<!-- 以下略 -->

<script>
  let ol = document.getElementById("ol");
  let g = ol.getElementsByTagName("li");
  let q = ol.querySelectorAll("li");
  let li1 = document.getElementById("li1");
  ol.removeChild(li1);                                          // li1 を削除
  document.getElementById('d11').textContent=g[0].textContent;
  document.getElementById('d21').textContent=q[0].textContent;
  document.getElementById("li2").textContent = "xxxxx";         // li2 の内容を変更
  document.getElementById('d12').textContent=g[0].textContent;  // g からは li1 の内容が削除されている
  document.getElementById('d22').textContent=q[1].textContent;  // q には li1 の内容が残っている
</script>

li1 を削除して、li2 の内容を "xxxxx" に変更しています。

その結果、getElementsByTagName で取得した g 内の最初の要素も削除され2番目の "bbbbb" が先頭の要素になっています。それに対して、querySelectorAll で取得した q は変更されず "aaaaa" が先頭の要素になっています。

ただし、要素の内容の変更は反映されるようで、li2 の内容はともに "xxxxx" となっています。

実行例

8.9.3  エレメントの属性

(1) hasAttribute、hasAttributeNS、hasAttributes

エレメント.hasAttribute(name)

指定の属性を持つかどうかを返す。

引数 name:属性名

戻り値:あり(true)、なし(false)


エレメント.hasAttributes()

何らかの属性を持つかかどうかを返す。

戻り値:あり(true)、なし(false)


記述例
<div id="id1" class="c1 c2 c3" style="display:none;">XXX</div>
<div id="d1"></div>
<!-- 以下略 -->

<script>
  let e = document.getElementById("id1");
  document.getElementById("d1").textContent=e.hasAttributes();
  document.getElementById("d2").textContent=e.hasAttribute("class");
  document.getElementById("d3").textContent=e.hasAttribute("xxx");
</script>

class という属性はあるので true、xxx はないので false になります。

実行例

SVG 要素などが属性を持つかどうかを調べるには名前空間を指定する必要があるので、次のメソッドを使用します。

エレメント.hasAttributeNS(namespace, name)

指定された名前空間に指定の属性を持つかどうかを返す。

引数 namespace:名前空間URI(例えば、XLink は http://www.w3.org/1999/xlink)

引数 name:属性名

戻り値:あり(true)、なし(false)


SVG での HREF は、名前空間が http://www.w3.org/1999/xlink に定義されています。そのため、参照するには、hasAttributeNS メソッドを使用し名前空間を指定する必要があります。

記述例
<svg id="svg" viewbox="0,0 150 90" width="150" height="90">
  <image id="image" x="50" y="10" width="74" height="74" xlink:href="bear.png"/>
</svg>
<div id="d1"></div>
<!-- 以下略 -->

<script>
  let img = document.getElementById("image");
  document.getElementById("d1").textContent=img.hasAttributeNS("http://www.w3.org/1999/xlink", "href");
  document.getElementById("d2").textContent=img.hasAttributeNS("http://www.w3.org/1999/xlink", "x");
  document.getElementById("d3").textContent=img.hasAttribute("href");   // 名前空間が違うから見つからない
  document.getElementById("d4").textContent=img.hasAttribute("x");      // SVG の要素でも通常の属性は hasAttribute
</script>

名前空間 http://www.w3.org/1999/xlink に href という属性はあるので true、x はないので false になります。

逆に、名前空間を指定しないと href は false、x は true になります。

実行例

(2) getAttribute、getAttributeNS、setAttribute、setAttributeNS、removeAttribute、removeAttributeNS

エレメント.getAttribute(name)

指定の属性値を返す

引数 name:属性名

戻り値:属性値


エレメント.setAttribute(name, value)

指定の属性に属性値を設定する

引数 name:属性名

引数 value:属性値(空白区切りで複数の属性値を設定できる)

戻り値:なし


エレメント.removeAttribute(name)

指定の属性を削除する

引数 name:属性名

戻り値:なし


記述例
<div id="id1" class="c1 c2 c3" style="display:none;">XXX</div>
<div id="id2" data-my-rank="プレミアム" data-max-number="10">YYY</div>    <!-- 独自データ属性 -->
<div id="d1"></div>
<!-- 以下略 -->

<script>
  let e = document.getElementById("id1");
  document.getElementById("d1").textContent=e.getAttribute("class");
  e.setAttribute("class", "xx");    // class 属性値を変更
  document.getElementById("d2").textContent=e.getAttribute("class");
  e.removeAttribute("class");       // class 属性値を削除
  document.getElementById("d3").textContent=e.getAttribute("class");
  
  e = document.getElementById("id2");
  document.getElementById("d11").textContent=e.getAttribute("data-my-rank");       // data-my-rank
  document.getElementById("d12").textContent=e.getAttribute("data-max-number");    // data-max-number
</script>

2番目と3番目の例は、setAttribute で変更した後の class 属性値と removeAttribute で削除した後の class 属性値を表示しています。

最後の2つは独自データ属性の例です。

実行例

SVG 要素などの属性を参照、設定するには名前空間を指定する必要があるので、次のメソッドを使用します。

エレメント.getAttributeNS(namespace, name)

指定された名前空間の属性値を返す

引数 namespace:名前空間URI(例えば、SVGは http://www.w3.org/2000/svg)

引数 name:属性名

戻り値:属性値


エレメント.setAttributeNS(namespace, name, value)

指定された名前空間に属性値を設定する

引数 namespace:名前空間URI(例えば、SVGは http://www.w3.org/2000/svg)

引数 name:属性名

引数 value:属性値(空白区切りで複数の属性値を設定できる)

戻り値:なし


エレメント.removeAttributeNS(namespace, name)

指定された名前空間の属性を削除する

引数 namespace:名前空間URI(例えば、SVGは http://www.w3.org/2000/svg)

引数 name:属性名

戻り値:なし


記述例
<svg id="svg" viewbox="0,0 0 0" width="0" height="0">
  <image id="image" x="50" y="10" width="74" height="74" xlink:href="../../figures/bear.png"/>
</svg>
<div id="d1"></div>
<!-- 以下略 -->

<script>
  let img = document.getElementById("image");
  document.getElementById("d1").textContent=img.getAttributeNS("http://www.w3.org/1999/xlink", "href");
  img.removeAttributeNS("http://www.w3.org/1999/xlink", "href");   // 削除
  document.getElementById("d2").textContent=img.hasAttributeNS("http://www.w3.org/1999/xlink", "href");
  img.setAttributeNS("http://www.w3.org/1999/xlink", "href", "../../figures/bear2.png");
  document.getElementById("d3").textContent=img.getAttributeNS("http://www.w3.org/1999/xlink", "href");
</script>

下から2つは、removeAttribute で削除した後の href 属性の有無と setAttribute で変更した後の href 属性値を表示しています。

実行例

(3) getAttributeNode、getAttributeNodeNS、setAttributeNode、setAttributeNodeNS、removeAttributeNode

エレメント.getAttributeNode(name)

指定の属性ノードを返す

引数 name:属性名

戻り値:属性ノード


エレメント.setAttributeNode(node)

指定の属性を設定する

引数 node:属性ノード

戻り値:変更前の属性ノード


エレメント.removeAttributeNode(node)

指定の属性ノードを削除する

引数 name:属性ノード

戻り値:削除された属性ノード


記述例
<div id="id1" class="c1 c2 c3" style="display:none;">XXX</div>
<div id="x" class="xxx" style="display:none;"></div>
<div id="d1"></div>
<!-- 以下略 -->

<script>
  let e = document.getElementById("id1");
  let c1 = e.getAttributeNode("class");
  document.getElementById("d1").textContent = c1.nodeValue;
  let x = document.getElementById("x");
  let c2 = x.getAttributeNode("class").cloneNode();       // クローン
  e.setAttributeNode("c2");    // class 属性値を変更
  c1 = e.getAttributeNode("class");
  document.getElementById("d2").textContent = c1.nodeValue;
  e.removeAttribute(c2);       // class 属性値を削除
  c1 = e.getAttributeNode("class");
  if (c1 != null) {
    document.getElementById("d3").textContent = c1.nodeValue;
  }
</script>

2番目と3番目の例は、setAttributeNode で変更した後の class 属性値と removeAttributeNode で削除した後の class 属性値を表示しています。

最後の2つは独自データ属性の例です。

実行例

SVG 要素などの属性を参照、設定するには名前空間を指定する必要があるので、次のメソッドを使用します。

エレメント.getAttributeNodeNS(namespace, name)

指定された名前空間の属性値を返す

引数 namespace:名前空間URI(例えば、SVGは http://www.w3.org/2000/svg)

引数 name:属性名

戻り値:属性ノード


エレメント.setAttributeNodeNS(namespace, name, node)

指定された名前空間に属性値を設定する

引数 namespace:名前空間URI(例えば、SVGは http://www.w3.org/2000/svg)

引数 name:属性名

引数 node:属性ノード

戻り値:変更前の属性ノード


記述例
<svg id="svg" viewbox="0,0 0 0" width="0" height="0">
  <image id="image" x="50" y="10" width="74" height="74" xlink:href="../../figures/bear.png"/>
  <image id="image2" x="50" y="10" width="74" height="74" xlink:href="../../figures/bear2.png"/>
</svg>
<div id="d1"></div>
<div id="d2"></div>

<script>
  let img = document.getElementById("image");
  let h1 = img.getAttributeNodeNS("http://www.w3.org/1999/xlink", "href");
  document.getElementById("d1").textContent = h1.nodeValue;
  let img2 = document.getElementById("image2");
  let h2 = img2.setAttributeNodeNS("http://www.w3.org/1999/xlink", "href").cloneNode();  // クローン
  img.setAttributeNodeNS(h2);    // href 属性値を変更
  h1 = img.getAttributeNodeNS("http://www.w3.org/1999/xlink", "href");
  document.getElementById("d2").textContent = h1.nodeValue;
</script>

2つ目は、setAttributeNodeNS で変更した後の href 属性値を表示しています。

実行例

8.9.4  エレメントの操作

HTML の各要素に対する操作です。

(1) スクロール

要素の内容をスクロールします。

エレメント.scrollTo(x, y)、エレメント.scrollBy(x, y)

要素の内容をスクロールして移動する。

引数 x:移動先の x 座標(scrollTo)、x 方向への移動量(scrollBy)

引数 y:移動先の y 座標(scrollTo)、y 方向への移動量(scrollBy)

戻り値:なし

scrollTo は、指定した位置を要素の左上にスクロールします。

記述例
<div id="scroll">A123456789<br>BB12345678<br>CCC1234567<br>DDDD123456<br>EEEEE12345<br>FFFFFF1234<br>GGGGGGG123<br>HHHHHHHH12<br>IIIIIIIII1</div><br>
<div>scrollTo(<input name="left" type="number" size="3" min="0" max="100" value="0" onchange="change();">, 
<input name="top" type="number" size="3" min="0" max="100" value="0" onchange="change();">)<br>

<script>
function change() {
  let top = document.f.top.value;
  let left = document.f.left.value;
  let s = document.getElementById('scroll');
  s.scrollTo(left, top);
}
</script>

左側の要素の内容をスクロールさせ、指定した位置を要素の左上に移動させます。

右側の要素は、スクロール位置を説明するために別途表示しています。

実行例

scrollBy は、指定したスクロール量だけスクロールします。

記述例
<div id="scroll">A123456789<br>BB12345678<br>CCC1234567<br>DDDD123456<br>EEEEE12345<br>FFFFFF1234<br>GGGGGGG123<br>HHHHHHHH12<br>IIIIIIIII1</div><br>
<div>scrollBy(<input name="left" type="number" size="3" min="-50" max="50" value="0" onchange="change();">, 
              <input name="top" type="number" size="3" min="-50" max="50" value="0" onchange="change();">)<br>

<script>
function change() {
  let top = document.f.top.value;
  let left = document.f.left.value;
  let s = document.getElementById('scroll');
  s.scrollBy(left, top);
  document.f.top.value = 0;
  document.f.left.value = 0;
}
</script>

左側の要素の内容を指定した量だけスクロールさせます。負数も指定できます。その後、入力された数値を 0にしています。

右側の要素は、スクロール位置を説明するために別途表示しています。

実行例

(2) 追加・置換・削除

自要素に対して、ノードまたは文字列を追加・置換します。また、自要素を削除します。

エレメント.before(要素[, 要素, ...])

要素をエレメントオブジェクトの直前に追加する。

引数 要素:ノード または 文字列

戻り値:なし

エレメント.append(要素[, 要素, ...])

要素をエレメントオブジェクトの内部の最後に追加する。

引数 要素:ノード または 文字列

戻り値:なし

エレメント.after(要素[, 要素, ...])

要素をエレメントオブジェクトの直後に追加する。

引数 要素:ノード または 文字列

戻り値:なし

エレメント.replaceChildren([要素, ...])

エレメントオブジェクトの内部を要素で置き換える。引数を指定しないと内部をすべて削除することになる。

引数 要素:ノード または 文字列

戻り値:なし

エレメント.remove()

エレメントオブジェクトの内部だけではなく、自身を含めてすべてを削除する。

戻り値:なし


before は直前に、append は内部のコンテンツの最後に、after は直後に追加します。

記述例
<div style="display:none;">
  <div id="id1"><br><p id="id11">XXX</p></div>
  <div id="id2"><p id="id21">XXX</p></div>
  <div id="id3"><p id="id31">XXX</p><br></div>
</div>
<div id="d1"></div>
<!-- 以下略 -->

<script>
  let d = document.getElementById("id1");
  let s = document.createElement("span");
  let p1 = document.getElementById("id11");
  p1.before("AA", s, "B");      // <p id="id11">XXX</p> の直前に追加
  document.getElementById("d1").textContent = d.innerHTML;
  
  d = document.getElementById("id2");
  let p2 = document.getElementById("id21");
  p2.append("AA", s, "B");      // <p id="id21">XXX</p> の中の最後に追加
  document.getElementById("d2").textContent = d.innerHTML;
  
  d = document.getElementById("id3");
  let p3 = document.getElementById("id31");
  p3.after("AA", s, "B");       // <p id="id31">XXX</p> の直後に追加
  document.getElementById("d3").textContent = d.innerHTML;
</script>

AA<span></span>B を追加しています。

実行例

要素に追加、挿入、変更、削除されます。

記述例
<p id="p1">replacing element</p>
<p id="p2">removing element</p>
<div id="initSwitch" class="switch" onClick="location.reload(false);" title="初期状態">初期状態</div> 
<div id="appendSwitch" class="switch" onClick="append();" title="追加">追加</div> 
<div id="insertSwitch" class="switch" onClick="insert();" title="挿入">挿入</div> 
<div id="modifySwitch" class="switch" onClick="modify();" title="変更">変更</div> 
<div id="removeSwitch" class="switch" onClick="remove();" title="削除">削除</div>
<script>
function append() {
  let sw = document.getElementById("removeSwitch");
  let p = document.createElement("p");
  p.textContent="appended element";
  p.style.color="red";
  sw.after(p);         // sw の後に追加する
}
function insert() {
  let p = document.createElement("p");
  p.textContent="inserted element";
  p.style.color="red";
  let sw = document.getElementById("initSwitch");
  sw.before(p);    // sw の前に追加する
}
function modify() {
  let p1 = document.getElementById("p1");
  let p = document.createElement("p");
  p.textContent="replaced element";
  p.style.color="red";
  p1.replaceChildren(p);    // p1 を p で置き換える
}
function remove() {
  let p2 = document.getElementById("p2");
  p2.remove();        // p2 を削除する
}
</script>

ボタンをクリックすると、指定要素に追加、挿入、変更、削除されます。

なお、記述例では省略してありますが、同じボタンはクリックできないようにしてあります。

実行例

8.9.5  イベント

HTML の各要素に対して、いろいろな操作(マウスを重ねる、クリックする、キー入力するなど)をすると、その都度イベントが発生しています。

(1) イベントリスナー

発生したイベントに対して処理を行いたいときに、イベントと関数を関連付けるためのメソッドが用意されています。なお、第3引数の useCapture については、「10.2  イベントの伝播」を参照してください。

エレメント.addEventListener(event, func, useCapture)

event 発生時に func を実行するようにイベントリスナーを設定する。

引数 event:イベントの種類

引数 func:関数(イベントハンドラ)

引数 useCapture:Capture(捕捉)フェーズを使用する(true)、使用しない(false) 規定値

戻り値:なし


エレメント.removeEventListener(event, func, useCapture)

指定した引数とまったく同じである、イベントリスナーを削除する。ただし、addEventListener のとき、第二引数に直接メソッドを記述していた場合は削除できない。

引数 event:イベントの種類

引数 func:関数(イベントハンドラ)

引数 useCapture:Capture(捕捉)フェーズを使用する(true)、使用しない(false) 規定値

戻り値:なし

記述例
<div onClick='add();'>addEventListener</div> <div onClick='removex();'>removeEventListener</div>
<div id='time'>現在時刻→<span id='x'></span></div>
<script>
var time = document.getElementById('time');
function add() {
  time.addEventListener('mousemove', now, false);
}
function removex() {                    // Chrome、Firefox、Sleipnir では remove は使えない
  document.getElementById('x').textContent="";
  time.removeEventListener('mousemove', now, false);
}
function now() {
  let t = new Date();
  document.getElementById('x').textContent=t.toLocaleDateString() + " " + t.toLocaleTimeString();
}
</script>

[addEventListener] ボタンで、時刻が表示されるよう id が time のエレメントにイベントリスナーを設定します。[removeEventListener] ボタンで、イベントリスナーを解除します。

「現在時刻」の文字の上でマウスを動かしてみてください。

実行例


(2) イベントの送信

HTML の各要素に対して、イベントを送信します。

イベントが送信された要素の内、少なくともひとつのイベントハンドラが preventDefault() を呼び出した場合は戻り値が false になります。preventDefault() は、そのイベントのデフォルトの動作をキャンセルしたいときに呼び出します。

エレメント.dispatchEvent(event)

イベントを送信する。

引数 event:イベント

戻り値:このイベントを処理したイベントハンドラが preventDefault() を呼び出した場合(false)、そうでなければ(true)

一つ目のチェックボックスは preventDefault() を実行していますので、チェックを付けたり消したりというデフォルトの動作は行われません。

記述例
<input id="check1" type="checkbox"> <input id="check2" type="checkbox">
 <div class="switch" onclick="fire();">クリック</div>

<script>
document.getElementById("check1").addEventListener("click", function(event){event.preventDefault();});

function fire() {
  let evt1;
  let evt2;
  try {
    evt1 = new MouseEvent("click", {"cancelable":true});  // Edge、Chrome、Firefox、Opera、Sleipnir 用
    evt2 = new MouseEvent("click", {"cancelable":true});
  }
  catch(x) {
    evt1 = document.createEvent("HTMLEvents");            // internet explorer、 Safari 用
    evt2 = document.createEvent("HTMLEvents");
    evt1.initEvent("click", true, true);
    evt2.initEvent("click", true, true);
  }
  document.getElementById("check1").dispatchEvent(evt1);            // click イベントを送る
  document.getElementById("check2").dispatchEvent(evt2);
}
</script>
実行例


ただし、dispatchEvent でイベントを送ってもデフォルトの処理が行われるかどうか微妙なようです(イベントは送られます)。

複数の要素に同じイベントを送ったときは、一つ目はチェックが付きますが、二つ目以降は付きません(厳密にいうと、イベントが発生したときには付くのですがその後消えます)。

しかし、別々のイベントを送ったときは、正しくデフォルトの処理が行われるようです。

記述例
<input id="check01" type="checkbox">A <input id="check02" type="checkbox">B <input id="check03" type="checkbox">C
 <div class="switch" onclick="fire();">クリック</div>
<input id="check11" type="checkbox">A <input id="check12" type="checkbox">B <input id="check13" type="checkbox">C

<script>
function fire() {
  let evt = getEvent();
  let evt1 = getEvent();
  let evt2 = getEvent();
  let evt3 = getEvent();
  document.getElementById("check01").dispatchEvent(evt);        // 同じ click イベントを送る
  document.getElementById("check02").dispatchEvent(evt);
  document.getElementById("check03").dispatchEvent(evt);
  document.getElementById("check11").dispatchEvent(evt1);       // 別々の click イベントを送る
  document.getElementById("check12").dispatchEvent(evt2);
  document.getElementById("check13").dispatchEvent(evt3);
}

function getEvent() {
  let evt;
  try {
    evt = new MouseEvent("click");              // Edge、Chrome、Firefox、Opera、Sleipnir 用
  }
  catch(x) {
    evt = document.createEvent("HTMLEvents");   // internet explorer、 Safari 用
    evt.initEvent("click", true, true);
  }
  return evt;
}
</script>
実行例


8.10   HTML 要素(HTMLElement)

HTMLElement オブジェクトは、任意の HTML 要素を表します。

HTMLElement は Element を継承していますので、Element のプロパティや機能を使用することができます。

Node Element HTMLElement

Element オブジェクトの主なプロパティとメソッドについて説明します。

8.10.1  エレメント情報

(1) エレメント情報

プロパティ
accessKey要素に割り当てられたアクセスキー
accessKeyLabelR/O要素に割り当てられたアクセスキーを含む文字列
contentEditable編集可能(yes)、編集不可(no)
isContentEditableR/O要素のコンテンツが編集可能(yes)、編集不可(no)
datasetR/O独自データ属性(data- の後ろの文字列。ただし、- を削除し、その後ろの文字を大文字にした名前のメンバーを持つ)
dir要素の書字方向
hiddenhidden 属性
innerText自身と子孫のコンテンツ(HTML を含まない)
langコンテンツの言語
outerText自身と子孫のコンテンツ(HTML を含まない)
stylestyle 属性のリスト
titletitle 属性値

記述例
<div id="id1" accessKey="a" dir="ltr" lang="en" title="タイトル" style="display:none;">AA<span>B</span></div>
<div id="id2" data-my-rank="プレミアム" data-max-number="10" style="display:none;">YYY</div>
<span id="d1"></span><br>
<span id="d21"></span>  <span id="d22"></span><br>
<span id="d3"></span><br>
<!-- 以下略 -->

<script>
  function dispStyle(style) {
    let s = "";
    for (let i = 0 ; i < style.length ; i++) {
      let t = style[i];
      s += t + ":" + style[t] + "; ";
    }
    return s;
  }
  let e = document.getElementById("id1");
  document.getElementById("d1").textContent=e.accessKey;
  document.getElementById("d21").textContent=e.isContentEditable;
  e.contentEditable = true;                 // contenteditable を true にする
  document.getElementById("d22").textContent=e.isContentEditable;
  document.getElementById("d3").textContent=e.dir;
  document.getElementById("d4").textContent=e.hidden;
  document.getElementById("d5").textContent=e.innerText;
  document.getElementById("d6").textContent=e.lang;
  document.getElementById("d7").textContent=e.outerText;
  document.getElementById("d8").textContent=dispStyle(e.style);
  document.getElementById("d9").textContent=e.title;

  e = document.getElementById("id2");
  document.getElementById("d11").textContent=e.dataset.myRank;     // data-my-rank
  document.getElementById("d12").textContent=e.dataset.maxNumber;  // data-max-number
</script>

HTML の内容を下側の枠の中に表示しています。エレメントの場合は ノード名(ノードタイプ)ローカル名、その他は ノード名(ノードタイプ)テキスト内容 を表示しています。なお、#text(3) のみの行は改行だと思われます。

実行例

innerText は、自身のコンテンツ(自身のタグを含まない内容のみ)を変更しますが、outerText は自身のタグも含めて変更します。

記述例
<div id="id11" style="display:none;">AAA<span id="id12">X<b>Y</b></span>BB</div>
<div id="id21" style="display:none;">AAA<span id="id22">X<b>Y</b></span>BB</div>

<span id="d11"></span>  <span id="d12"></span><br>
<span id="d21"></span>  <span id="d22"></span><br>

<script>
  let e11 = document.getElementById("id11");
  let e21 = document.getElementById("id21");
  document.getElementById("d11").textContent=e11.innerHTML;
  document.getElementById("d21").textContent=e21.innerHTML;
  
  document.getElementById("id12").innerText = "ZZZZZ";     // "ZZZZZ" を innerText に代入する
  document.getElementById("id22").outerText = "ZZZZZ";     // "ZZZZZ" を outerText に代入する
  document.getElementById("d12").textContent=e11.innerHTML;
  document.getElementById("d22").textContent=e21.innerHTML;
</script>

innerText は、id12 のコンテンツである X<b>Y</b> を ZZZZZ で置き換えています。

outerText は、id22 のタグを含めた要素そのものである <span id="id22">X<b>Y</b></span> を ZZZZZ で置き換えています。

実行例

また、innerText と textContent は若干の違いがあります。

記述例
<div id="str" style="display:none">	A     B
C</div>
<table>
  <tr><td id="d01"></td><td id="d02"></td><td> = </td><td>undefined</td></tr>
  <tr><td id="d11"></td><td id="d12"></td><td> = </td><td>null</td></tr>
  <tr><td id="d21" style="white-space:normal;"></td><td id="d22" style="white-space:normal;"></td><td> = </td><td>innerText</td></tr>
  <tr><td id="d31" style="white-space:pre;"></td><td id="d32" style="white-space:pre;"></td><td> = </td><td>textContent</td></tr>
</table>
<br>
<table>
  <tr><td id="d1" style="white-space:pre;"></td><td> = </td><td>innerText</td></tr>
  <tr><td id="d2" style="white-space:pre;"></td><td> = </td><td>textContent</td></tr>
</table>

<script>
  window.addEventListener("load", function() {
    document.getElementById('d01').innerText=undefined;
    document.getElementById('d02').textContent=undefined;

    document.getElementById('d11').innerText=null;
    document.getElementById('d12').textContent=null;

    let s = "\tA     B\nC";
    document.getElementById('d21').innerText=s;
    document.getElementById('d22').textContent=s;

    document.getElementById('d31').innerText=s;
    document.getElementById('d32').textContent=s;

    document.getElementById('d1').innerHTML=document.getElementById('str').innerText;
    document.getElementById('d2').innerHTML=document.getElementById('str').textContent;
  } , false);
</script>

前半部分では代入される側(左辺)が innerText と textContent でどう違うのかを示しています。スタイルシートの white-space 属性の値によっても違うようです。ちなみに、代入している文字列は "(タブ)A(連続した空白)B(改行)C" です。

後半部分は、代入する側(右辺)が innerText と textContent でどう違うのかを示しています。代入するエレメントの内容はやはり "(タブ)A(連続した空白)B(改行)C" です。

実行例

(2) オフセット情報

プロパティ
offsetParentR/Oオフセット座標の基準となる要素
(position属性が relative、absolute または fixed である直近の祖先要素)
offsetHeightR/Oボーダーを含む要素全体の高さ
offsetLeftR/O水平方向のオフセット
offsetTopR/O垂直方向のオフセット
offsetWidthR/Oボーダーを含む要素全体の横幅

記述例
<style>
div.grandParent {
  background-color:lavenderblush;
  width:250px;
  padding:10px 40px 20px 30px;
}
div.parent {
  background-color:lightcyan;
  padding:15px 0px 25px 35px;
}
div.child {
  background-color:lawngreen;
  width:50px;
  margin:12px 42px 22px 32px;
  border:solid 10px limegreen;
}
</style>

<div id="grandParent" class="grandParent" style="position:relative;"><div id="parent" class="parent"><div id="child" class="child">XXX</div></div></div>
<div id="d1"></div>
<!-- 以下略 -->

<script>
  let c = document.getElementById("child");
  document.getElementById("d1").textContent=c.offsetParent.id;
  document.getElementById("d2").innerHTML=c.offsetTop;
  document.getElementById("d3").innerHTML=c.offsetLeft;
  document.getElementById("d4").innerHTML=c.offsetHeight;
  document.getElementById("d5").innerHTML=c.offsetWidth;
</script>

parent の要素にはありませんが、grandParent の要素には relative である position属性がありますので、child の要素のオフセットの基準は grandParent の要素になります。

矢印や文字列は理解の助けになるように別途表示しています。

破線の矩形は child のマージン範囲を示すために別途表示しています。

実行例

8.10.2  エレメントの操作

(1) フォーカス

キーボードフォーカスを設定します。

エレメント.focus()

指定された要素にフォーカスを設定する。

戻り値:なし

エレメント.blur()

指定された要素にフォーカスを取り除く。

戻り値:なし

記述例
<input id="id1" value="初期値"></input><br><br>
<button onclick="id1.focus();">フォーカスを当てる</button>&nbsp;&nbsp;<button onclick="id1.blur();">フォーカスを外す</button>
実行例

(2) クリック

click イベントを発行します。

エレメント.click()

指定された要素の click イベントを発行する。

戻り値:なし

記述例
<div id="d1" onmouseover="this.textContent='&nbsp;'"></div>
<button onclick="id1.textContent='SW1 をクリック';">SW1</button>&nbsp;&nbsp;<button onclick="sw1.click();">SW2</button>

SW1 をクリックすると、"SW1 をクリック" と表示されます。SW2 をクリックすると、SW1 に click イベントを発行するので同じように "SW1 をクリック" と表示されます。

なお、"SW1 をクリック" にマウスポインタを重ねると文字列が消えます。

実行例

8.10.3  自律型カスタム要素

カスタム要素は、Webコンポーネントと呼ばれる技術群のひとつです。独自のメソッドやプロパティ、イベントなどを持つ、独自の要素を定義することができます。

カスタム要素は、組み込みの HTML 要素と同じように使用することができます。

カスタム要素には2種類ありますが、そのうち HTMLElement クラスを継承して新規の要素として定義したものが、自律型カスタム要素です。

(1) 自律型カスタム要素クラスの構成

自律型カスタム要素クラスは、HTMLElement を継承して作成します。

記述例
<script>
class カスタム要素クラス extends HTMLElement {
  constructor() {  // コンストラクタ
    super();  // HTMLElement のコンストラクタを呼び出す
    // インスタンス生成時の処理
  }
  connectedCallback() {  // 要素が挿入されたときに呼び出される
  }
  disconnectedCallback() {  // 要素が削除されたときに呼び出される
  }
  adoptedCallback(oldDoc, newDoc) {  // 要素が移動されたときに呼び出される
  }
  attributeChangedCallback(name, oldValue, newValue) {  // 指定した属性が追加、変更、削除されたときに呼び出される
  }
}
</script>

カスタム要素のクラスには、次のようなメソッドが必要です。これらのメソッドは、カスタム要素がドキュメントに挿入されたり削除されたりするたびに呼び出されるコールバックメソッドです。挿入されたり削除されたりしたときに必要な処理をこの中に記述します。

また、このほかに、属性が追加、変更、削除された場合に attributeChangedCallback() が呼び出される、属性の名前を指定しておく必要があります(指定しておかないと、追加、変更、削除されても attributeChangedCallback() が呼び出されません)。

メソッド引数機能
connectedCallback()カスタム要素がドキュメントに新規あるいは移動によって挿入されたときに呼び出される
disconnectedCallback()カスタム要素がドキュメントから削除あるいは移動によって取り除かれたときに呼び出される
adoptedCallback(oldDoc, newDoc)oldDoc:移動元のドキュメント
newDoc:移動先のドキュメント
カスタム要素がドキュメント間で移動(adoptNode)されたときに呼び出される
attributeChangedCallback
          (name, oldValue, newValue)
name:変更のあった属性名
oldValue:変更前の値
newValue:変更後の値
指定した属性(注)が追加、変更、削除されたときに呼び出される
(注)属性の指定方法には次の2つがある。
 ○カスタム要素のクラスに、属性のリストを持つ静的変数を定義する
  static observedAttributes = ["属性", ...];    // 属性のリスト([] は省略ではなくリストの意味)
 ○カスタム要素のクラスに、属性のリストを返す静的メソッドを定義する
  static get observedAttributes() {
    return ["属性", ...];    // 属性のリスト([] は省略ではなくリストの意味)
  }

注意

属性は、小文字で定義する必要があります。

カスタム要素で指定するときは、大文字小文字を問いません。


(2) 自律型カスタム要素名の定義

カスタム要素は、既存の組み込み HTML 要素と同じように使用するには、HTML のタグとして使用できる名前を付ける必要があります。

ただし、カスタム要素の名前には、通常の要素と区別できるようにするためにハイフン (-) を含めます。そして、次のような宣言をして、カスタム要素の名前とカスタム要素のクラスを関係付けます。

customElements.define(" 自律型カスタム要素の名前", カスタム要素クラス);


(3) 自律型カスタム要素の動的生成

自律型カスタム要素を、Javascript で動的に生成するには、既存の組み込み HTML 要素と同じように、次のように行います。

ドキュメント.createElement("カスタム要素の名前")

カスタム要素の名前と関係付けられた 自律型カスタム要素のインスタンスを生成する。

引数 カスタム要素の名前:customElements.define() でカスタム要素クラスと関係付けた名前

戻り値:HTMLElement インスタンス



自律型カスタム要素を、Javascript で動的に生成したり、変更・削除したときに、4つのメソッドがどのようなタイミングで呼び出されるかを確認できる例です。親ドキュメントに iframe 要素があり、その中に別のドキュメント(sub.htm)が表示されています。

追加では、親ドキュメントにカスタム要素を追加しますので、connectedCallback が呼び出されます。

変更では、カスタム要素の属性を変更していますので、attributeChangedCallback が呼び出されます。

移動では、元のドキュメントから iframe 内のドキュメントにカスタム要素を移しています。このとき、カスタム要素が、元のドキュメントから削除、iframe 内のドキュメントに移動、そして追加が行われますので、disconnectedCallback、adoptedCallback、connectedCallback が順に呼び出されます。

削除では、元のドキュメントからカスタム要素を削除していますので、disconnectedCallback が呼び出されます。

記述例
<span id="d"><br></span><br>
<span class="switch" onclick="init();">初期状態</span>
<span class="switch" onclick="insert();">追加</span>
<span class="switch" onclick="modify();">変更</span>
<span class="switch" onclick="move();">移動</span>
<span class="switch" onclick="remove();">削除</span>
<iframe src="sub.htm" width="200px" height="40px"></iframe>

<script>
class CustomElement extends HTMLElement {
  static observedAttributes = ["attr"];  // 追加、変更、削除を監視する属性を指定する
  constructor() {  // コンストラクタ
    super();
  }
  connectedCallback() {  // 要素が追加されたときに呼び出される
    d.innerHTML += "connectedCallback<br>";
  }
  disconnectedCallback() {  // 要素が削除されたときに呼び出される
    d.innerHTML += "disconnectedCallback<br>";
  }
  adoptedCallback(oldDoc, newDoc) {  // 要素が移動されたときに呼び出される
    d.innerHTML += "adoptedCallback<br>";
  }
  attributeChangedCallback(name, oldValue, newValue) {  // 属性が追加、変更、削除されたときに呼び出される
    d.innerHTML += "attributeChangedCallback<br>";
  }
}
customElements.define("custom-element", CustomElement);  // カスタム要素の名前とカスタム要素のクラスを関係付ける

function init() {
  location.reload(false);
}
function insert() {
  d.textContent = "";
  let e = document.createElement("custom-element");  // カスタム要素を生成する
  e.style.backgroundColor = "yellow";
  e.innerHTML = "custom-element<br><br>";
  let f = document.getElementsByTagName("iframe")[0];
  document.body.insertBefore(e, f);  // ドキュメントに追加する
}
function modify() {
  d.textContent = "";
  let e = document.getElementsByTagName("custom-element")[0];  // カスタム要素を取得する
  e.style.backgroundColor = "lightgreen";
  e.setAttribute("attr", "a");  // attr 属性を変更する
}
function move() {
  d.textContent = "";
  let f = document.getElementsByTagName("iframe")[0];  // iframe 要素を取得する
  let fd = f.contentDocument;
  let e = document.getElementsByTagName("custom-element")[0];  // カスタム要素を取得する
  fd.body.appendChild(document.adoptNode(e));  // iframe のドキュメントに移動する
}
function remove() {
  d.textContent = "";
  let e = document.getElementsByTagName("custom-element")[0];  // カスタム要素を取得する
  document.body.removeChild(e);  // ドキュメントから削除する
}
</script>
sub.htm
  <body>
     <!-- 何も記述がない(iframe に表示されるドキュメント) -->
  </body>
表示例


(4) 自律型カスタム要素の HTML での利用

自律型カスタム要素を HTML の中に、既存の組み込み HTML 要素と同じように、タグとして記述することもできます。ただし、カスタム要素は必ず終了タグを記述する必要もあります。

<自律型カスタム要素の名前 [属性="属性値" ...]>コンテンツ</自律型カスタム要素の名前>

例として、小数点以下の桁数を指定できる数値要素を作成してみます。

ただし、カスタム要素の textContent を参照する場合、customElements.define() メソッドは、カスタム要素を記述した後に宣言する必要があるようです。

記述例(decimalFraction.js)
class DecimalFractionElement extends HTMLElement {
  static observedAttributes = ["decimalplace"];     // 大文字はダメ(decimalPlace)
  constructor() {  // コンストラクタ
    super();
  }
  connectedCallback() {  // 要素が挿入されたときに呼び出される
    this.style.textAlign = "right";
    this.style.display = "inline-block";
    if (this.attributes["decimalplace"] == undefined)
      this.textContent = this.roundDown(this.textContent, 2);  // 規定値:2
  }
  attributeChangedCallback(name, oldValue, newValue) {  // 属性が追加、変更、削除されたときに呼び出される
    if (name == "decimalplace") {
      if (oldValue != newValue)
        this.textContent = this.roundDown(this.textContent, newValue);
    }
  }
  roundDown(num, d) {
    let n = Number.parseFloat(num);
    return Number.isNaN(n) ? num : n.toFixed(d);
  }
}
記述例

customElements.define() メソッドをカスタム要素を記述した後に記述

<script src="decimalFraction.js"></script>
    
<div>[<decimal-fraction decimalPlace="3">123.45678</decimal-fraction>]</div>
<div>[<decimal-fraction>-123.456</decimal-fraction>]</div>
<div>[<decimal-fraction>12</decimal-fraction>]</div>
<script>
// ここだと OK
customElements.define("decimal-fraction", DecimalFractionElement);
</script>
記述例

customElements.define() メソッドをカスタム要素を記述する前に記述

<script src="decimalFraction.js"></script>
    
<script>
// ここだと NG
customElements.define("decimal-fraction", DecimalFractionElement);
</script>
<div>[<decimal-fraction decimalPlace="3">123.45678</decimal-fraction>]</div>
<div>[<decimal-fraction>-123.456</decimal-fraction>]</div>
<div>[<decimal-fraction>12</decimal-fraction>]</div>

decimal-fraction 要素が記述された時点では未定義の要素として作成されます。そして、customElements.define() 後に decimal-fraction 要素として再定義されます。

表示例

decimal-fraction 要素の開始タグが記述された時点では textContent に数値が読み込まれていませんので、"" となります。

表示例

注意

カスタム要素の textContent を参照する場合、customElements.define() メソッドは、カスタム要素を記述した後に宣言する必要があるようです。

カスタム要素を記述する前に customElements.define() メソッドの宣言があると、textContent は "" のままです。理由としては、カスタム要素の開始タグの時点で、connectedCallback() が呼ばれてしまい、textContent がまだ設定されていないからだと思われます。


注意

<decimal-fraction decimalPlace="3">123.45678</decimal-fraction> のように、追加・変更・削除の監視対象となる属性を持つカスタム要素を記述した場合、attributeChangedCallback メソッド、connectedCallback メソッドの順に呼び出されますので注意してください。


8.10.4  カスタマイズされた組み込み要素

(1) カスタマイズされた組み込み要素の構成

カスタマイズされた組み込み要素は、既存の要素のクラスを継承して作成します。

主なタグ名とクラス名は次のように対応しています。

タグ名クラス名
aHTMLAnchorElement
areaHTMLAreaElement
audioHTMLAudioElement
buttonHTMLButtonElement
captionHTMLTableCaptionElement
dlHTMLDListElement
divHTMLDivElement
formHTMLFormElement
タグ名クラス名
iframeHTMLIFrameElement
imageHTMLImageElement
inputHTMLInputElement
liHTMLLIElement
mediaHTMLMediaElement
olHTMLOListElement
pHTMLParagraphElement
selectHTMLSelectElement
タグ名クラス名
spanHTMLSpanElement
th、tdHTMLTableCellElement
tableHTMLTableElement
trHTMLTableRowElement
textareaHTMLTextAreaElement
ulHTMLUListElement
videoHTMLVideoElement

継承については、「7.1.6 継承」を参照してください。



記述例
<script>
class カスタム要素クラス extends 既存要素のクラス {
  constructor() {  // コンストラクタ
    super();  // HTMLElement のコンストラクタを呼び出す
    // インスタンス生成時の処理
  }
  connectedCallback() {  // 要素が挿入されたときに呼び出される
  }
  disconnectedCallback() {  // 要素が削除されたときに呼び出される
  }
  adoptedCallback(oldDoc, newDoc) {  // 要素が移動されたときに呼び出される
  }
  attributeChangedCallback(name, oldValue, newValue) {  // 指定した属性が追加、変更、削除されたときに呼び出される
  }
}
</script>

カスタム要素のクラスには、次のようなメソッドが必要です。これらのメソッドは、カスタム要素がドキュメントに挿入されたり削除されたりするたびに呼び出されるコールバックメソッドです。挿入されたり削除されたりしたときに必要な処理をこの中に記述します。

また、このほかに、属性が追加、変更、削除された場合に attributeChangedCallback() が呼び出される、属性の名前を指定しておく必要があります(指定しておかないと、追加、変更、削除されても attributeChangedCallback() が呼び出されません)。

メソッド引数機能
connectedCallback()カスタム要素がドキュメントに新規あるいは移動によって挿入されたときに呼び出される
disconnectedCallback()カスタム要素がドキュメントから削除あるいは移動によって取り除かれたときに呼び出される
adoptedCallback(oldDoc, newDoc)oldDoc:移動元のドキュメント
newDoc:移動先のドキュメント
カスタム要素がドキュメント間で移動(adoptNode)されたときに呼び出される
attributeChangedCallback
          (name, oldValue, newValue)
name:変更のあった属性名
oldValue:変更前の値
newValue:変更後の値
指定した属性(注)が追加、変更、削除されたときに呼び出される
(注)属性の指定方法には次の2つがある。
 ○カスタム要素のクラスに、属性のリストを持つ静的変数を定義する
  static observedAttributes = ["属性", ...];    // 属性のリスト([] は省略ではなくリストの意味)
 ○カスタム要素のクラスに、属性のリストを返す静的メソッドを定義する
  static get observedAttributes() {
    return ["属性", ...];    // 属性のリスト([] は省略ではなくリストの意味)
  }

注意

属性は、小文字で定義する必要があります。

カスタム要素で指定するときは、大文字小文字を問いません。


(2) カスタマイズされた組み込み要素名の定義


カスタム要素は、既存の組み込み HTML 要素と同じように使用するには、HTML のタグとして使用できる名前を付ける必要があります。

ただし、カスタム要素の名前には、通常の要素と区別できるようにするためにハイフン (-) を含めます。そして、次のような宣言をして、カスタム要素の名前とカスタム要素のクラスを関係付けます。

また、extends: に続いて機能を拡張する既存の組み込み HTML 要素名を指定します。

customElements.define("カスタム要素の名前", カスタム要素クラス, { extends: "既存要素の名前" });


(3) カスタマイズされた組み込み要素の動的生成

カスタマイズされた組み込みカスタム要素を、Javascript で動的に生成するには、次のように行います。

ドキュメント.createElement("既存要素の名前", { is: "カスタム要素の名前" })

カスタム要素の名前と関係付けられた カスタマイズされた組み込みカスタム要素のインスタンスを生成する。

引数 既存要素の名前:customElements.define() でカスタム要素クラスと関係付けた名前

引数 カスタム要素の名前:customElements.define() の extends: で指定した名前

戻り値:HTMLElement インスタンス



自律型カスタム要素を、Javascript で動的に生成したり、変更・削除したときに、4つのメソッドがどのようなタイミングで呼び出されるかを確認できる例です。親ドキュメントに iframe 要素があり、その中に別のドキュメント(sub.htm)が表示されています。

追加では、親ドキュメントにカスタム要素を追加しますので、connectedCallback が呼び出されます。

変更では、カスタム要素の属性を変更していますので、attributeChangedCallback が呼び出されます。

移動では、元のドキュメントから iframe 内のドキュメントにカスタム要素を移しています。このとき、カスタム要素が、元のドキュメントから削除、iframe 内のドキュメントに移動、そして追加が行われますので、disconnectedCallback、adoptedCallback、connectedCallback が順に呼び出されます。

削除では、元のドキュメントからカスタム要素を削除していますので、disconnectedCallback が呼び出されます。

記述例
<span id="d"><br></span><br>
<span class="switch" onclick="init();">初期状態</span>
<span class="switch" onclick="insert();">追加</span>
<span class="switch" onclick="modify();">変更</span>
<span class="switch" onclick="move();">移動</span>
<span class="switch" onclick="remove();">削除</span>
<iframe src="sub.htm" width="200px" height="40px"></iframe>

<script>
class CustomElement extends HTMLSpanElement {
  static observedAttributes = ["attr"];  // 追加、変更、削除を監視する属性を指定する
  constructor() {  // コンストラクタ
    super();
  }
  connectedCallback() {  // 要素が追加されたときに呼び出される
    d.innerHTML += "connectedCallback<br>";
  }
  disconnectedCallback() {  // 要素が削除されたときに呼び出される
    d.innerHTML += "disconnectedCallback<br>";
  }
  adoptedCallback(oldDoc, newDoc) {  // 要素が移動されたときに呼び出される
    d.innerHTML += "adoptedCallback<br>";
  }
  attributeChangedCallback(name, oldValue, newValue) {  // 属性が追加、変更、削除されたときに呼び出される
    d.innerHTML += "attributeChangedCallback<br>";
  }
}
customElements.define("custom-element", CustomElement, { extends: "span" });  // カスタム要素の名前とカスタム要素のクラスを関係付ける

function init() {
  location.reload(false);
}
function insert() {
  d.textContent = "";
  let e = document.createElement("span", { is: "custom-element" });  // カスタマイズされた組み込み要素を生成する
  e.id = "c";  // カスタム要素の識別のため id を付ける
  e.style.backgroundColor = "yellow";
  e.innerHTML = "custom-element<br><br>";
  let f = document.getElementsByTagName("iframe")[0];
  document.body.insertBefore(e, f);  // ドキュメントに追加する
}
function modify() {
  d.textContent = "";
  let e = document.querySelector("span[id='c']");  // カスタマイズされた組み込み要素を取得する
  e.style.backgroundColor = "lightgreen";
  e.setAttribute("attr", "a");  // attr 属性を変更する
}
function move() {
  d.textContent = "";
  let f = document.getElementsByTagName("iframe")[0];  // iframe 要素を取得する
  let fd = f.contentDocument;
  let e = document.querySelector("span[id='c']");  // カスタマイズされた組み込み要素を取得する
  fd.body.appendChild(document.adoptNode(e));  // iframe のドキュメントに移動する
}
function remove() {
  d.textContent = "";
  let e = document.querySelector("span[id='c']");  // カスタマイズされた組み込み要素を取得する
  document.body.removeChild(e);  // ドキュメントから削除する
}
</script>
sub.htm
  <body>
     <!-- 何も記述がない(iframe に表示されるドキュメント) -->
  </body>
表示例

注意

カスタマイズされた組み込み要素を生成する方法として次の2つがありますが、どちらも問題があります。

  ドキュメント.createElement("span", { is: "custom-element" });

この方法では、is が属性と見なされないためか、querySelector("span[is]") で取得できません。

  ドキュメント.createElement("span");
  e.setAttribute("is", "custom-element");

この方法では、is が単なる属性となり、is としての機能が動作せず、ドキュメントに追加しても connectedCallback() が呼び出されません。





(4) 自律型カスタム要素の HTML での利用

カスタマイズされた組み込み要素を HTML の中で使用するには、既存の組み込み要素の is 属性にカスタマイズされた組み込み要素の名前を指定します。

<既存の組み込み要素の名前 [属性="属性値" ...] is="カスタマイズされた組み込み要素の名前">コンテンツ</既存の組み込み要素の名前>

例として、小数点以下の桁数を指定できる数値要素を作成してみます。

ただし、カスタム要素の textContent を参照する場合、customElements.define() メソッドは、カスタム要素を記述した後に宣言する必要があるようです。

記述例(decimalFraction.js)
class DecimalFractionElement extends HTMLSpanElement {
  static observedAttributes = ["decimalplace"];     // 大文字はダメ(decimalPlace)
  constructor() {  // コンストラクタ
    super();
  }
  connectedCallback() {  // 要素が挿入されたときに呼び出される
    this.style.textAlign = "right";
    this.style.display = "inline-block";
    if (this.attributes["decimalplace"] == undefined)
      this.textContent = this.roundDown(this.textContent, 2);  // 規定値:2
  }
  attributeChangedCallback(name, oldValue, newValue) {  // 属性が追加、変更、削除されたときに呼び出される
    if (name == "decimalplace") {
      if (oldValue != newValue)
        this.textContent = this.roundDown(this.textContent, newValue);
    }
  }
  roundDown(num, d) {
    if (!Number.isNaN(num) && num != "") {
      let n = Number.parseFloat(num);
      return n.toFixed(d);
    }
  }
}
記述例

カスタム要素を使用した後に記述

<script src="decimalFraction.js"></script>
    
<div>[<span is="decimal-fraction" decimalPlace="3">123.45678</span>]</div>
<div>[<span is="decimal-fraction">-123.456</span>]</div>
<div>[<span is="decimal-fraction">12</span>]</div>
<script>
// ここだと OK
customElements.define("decimal-fraction", DecimalFractionElement, { extends: "span" });
</script>
記述例

カスタム要素を使用する前に記述

<script src="decimalFraction.js"></script>
    
<script>
// ここだと NG
customElements.define("decimal-fraction", DecimalFractionElement, { extends: "span" });
</script>
<div>[<span is="decimal-fraction" decimalPlace="3">123.45678</span>]</div>
<div>[<span is="decimal-fraction">-123.456</span>]</div>
<div>[<span is="decimal-fraction">12</span>]</div>

カスタマイズされた span 要素が記述された時点ではdecimal-fraction が未定義なので、通常の span 要素として作成されます。そして、customElements.define() 後に decimal-fraction でカスタマイズされた span 要素として再定義されます。

表示例

decimal-fraction でカスタマイズされた span 要素の開始タグが記述された時点では textContent は設定されていませんので、"" となります。

表示例

注意

カスタム要素の textContent を参照する場合、customElements.define() メソッドは、カスタム要素を記述した後に宣言する必要があるようです。

カスタム要素を記述する前に customElements.define() メソッドの宣言があると、textContent は "" のままです。理由としては、カスタム要素の開始タグの時点で、connectedCallback() が呼ばれてしまい、textContent がまだ設定されていないからだと思われます。


注意

<span is="decimal-fraction" decimalPlace="3">123.45678</span> のように、追加・変更・削除の監視対象となる属性を持つカスタム要素を記述した場合、attributeChangedCallback メソッド、connectedCallback メソッドの順に呼び出されますので注意してください。


8.11   フォーム(HTMLFormElement)

document の forms プロパティでフォーム要素(HTMLFormElement)のリストを得ることができます。

HTMLFormElement は HTMLElement を継承していますので、HTMLElement のプロパティや機能を使用することができます。

Node Element HTMLElement HTMLFormElement

各フォーム要素は、リストの要素番号を指定し、

  let f = document.forms[0];    // 最初の form 要素

のように参照することができます。また、フォーム要素の name 属性があれば name で参照することもできます。

  let f = document.f1;          // <form name="f1" ...
  let f = document.forms["f1"];

フォーム要素の主なプロパティとメソッドについて説明します。

8.11.1  フォーム要素

(1) フォーム情報

プロパティ
acceptCharsetR/Oこのフォームで使用可能な文字エンコーディング名(複数ある場合は 空白 区切り)
actionデータの送信先の URI
elementsフォーム内のフォーム部品のリスト(HTMLFormControlsCollection)
enctypeエンコードタイプ
lengthR/Oフォーム内のフォーム部品の数
methodサーバーにデータを送る形式(get または post)
nameR/Oフォームの名前
target表示ターゲット
記述例
<form name="f1" action="http://foo.com/exec.htm" method="get" target="_top" enctype="text/plain" accept-charset="UTF-8 Shift_JIS">
  <input type="text">
  <input type="password">
  <button>
</form>
<div id="d1"></div>
<!-- 以下略 -->

<script>
  function dispList(list) {
    let s = "";
    for (let i = 0 ; i < list.length ; i++) {
      s += list[i].tagName + " " + list[i].type + "<br>";
    }
    return s;
  }
let f = document.forms[0];          // 最初の form 要素
document.getElementById("d1").textContent=f.name;
document.getElementById("d2").textContent=f.method;
document.getElementById("d3").textContent=f.action;
document.getElementById("d4").textContent=f.target;
document.getElementById("d5").textContent=f.enctype;
document.getElementById("d6").textContent=f.acceptCharset;
document.getElementById("d7").innerHTML=dispList(f.elements);
</script>
実行例

elementsでは、フォーム要素に含まれるのフォーム部品のリスト(HTMLFormControlsCollection)を得ることができます。

フォーム部品には次のようなものがあります。

フォーム要素とクラスの対応
要素クラス
buttonHTMLButtonElement
inputHTMLInputElement
outputHTMLOutputElement
selectHTMLSelectElement
textareaHTMLTextAreaElement

各フォーム部品は、リストの要素番号を指定し、

  let e = document.f1.elements[0];    // 最初のフォーム部品

のように参照することができます。また、フォーム部品の name 属性があれば name で参照することもできます。

  let e = document.f1.e1;             // <input name="e1" ...
  let e = document.f1.elements["e1"];

(2) 送信、リセット

form 要素の input type="submit" や input type="reset" 要素と同じことを Javascript で行うことができます。

form 要素の submit() や reset() を呼び出します。

フォーム.submit()

フォームを送信する(送信ボタンをクリックするのと同じ動作をする)。

戻り値:なし


フォーム.reset()

フォームを初期状態にリセットする(リセットボタンをクリックするのと同じ動作をする)。

戻り値:なし

記述例
<form name="f1" action="#">
  コード:<input type="text" name="param" value="A001"><input type="hidden" name="value" value="0">     
   <div onClick="document.f1.value.value='1';document.f1.submit();">追加</div>
   <div onClick="document.f1.value.value='2';document.f1.submit();">削除</button>
   <div onClick="document.getElementById('params').textContent='&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;';document.f1.reset();">リセット</button>
</form>

[追加]と[削除]という2つの送信ボタンがありますので、区別がつくように type='hidden' とした name='value' のパラメータを用意しています。[追加]ボタンは '1' を、[削除]ボタンは '2' を設定して submit() を実行しています。[リセット]ボタンは reset() を実行しています。

実行例

8.11.2  Input フォーム部品(HTMLInputElement)

HTMLInputElement オブジェクトは、任意の input 要素を表します。

HTMLInputElement は HTMLElement を継承していますので、HTMLElement のプロパティや機能を使用することができます。

Node Element HTMLElement HTMLInputElement

(1) フォーム部品情報

プロパティ
formR/Oフォーム部品を包含するフォームオブジェクト(HTMLFormElement
autofocusautofocus 属性値
disableddisabled 属性値
namename 属性値
requiredrequired 属性値
typetype 属性値
valuevalue 属性値
記述例
<form name="f1" action="#">
  <input type="text" name="e1" autofocus="true" value="初期値">
  <textarea disabled="true" name="e2" autofocus="true">未使用<textarea>
  <input type="submit" name="e3" value="送信">
</form>
<span id="d11"></span> <span id="d12"></span> <span id="d13"></span><br>
<!-- 以下略 -->

<script>
let f = document.forms[0];
document.getElementById("d11").textContent=f.e1.tagName;
document.getElementById("d21").textContent=f.e1.type;
document.getElementById("d31").textContent=f.e1.value;
document.getElementById("d41").textContent=f.e1.name;
document.getElementById("d51").textContent=f.e1.autofocus;
document.getElementById("d61").textContent=f.e1.disabled;
document.getElementById("d71").textContent=f.e1.form.name;
document.getElementById("d12").textContent=f.e2.tagName;
document.getElementById("d22").textContent=f.e2.type;
document.getElementById("d32").textContent=f.e2.value;
document.getElementById("d42").textContent=f.e2.name;
document.getElementById("d52").textContent=f.e2.autofocus;
document.getElementById("d62").textContent=f.e2.disabled;
document.getElementById("d72").textContent=f.e2.form.name;
document.getElementById("d13").textContent=f.e3.tagName;
document.getElementById("d23").textContent=f.e3.type;
document.getElementById("d33").textContent=f.e3.value;
document.getElementById("d43").textContent=f.e3.name;
document.getElementById("d53").textContent=f.e3.autofocus;
document.getElementById("d63").textContent=f.e3.disabled;
document.getElementById("d73").textContent=f.e3.form.name;
</script>

form はオブジェクトが返るため、この例では form の name 属性を表示しています。

実行例

(2) input 要素のプロパティ

○ type=text、number、search、tel、url、email、date、time などのプロパティ

type が text や number などである input 要素に適用される主なプロパティには次のようなものがあります。

プロパティ
autocompleteautocomplete 属性
defaultValue元々の value 値(初期文字列)
maxmax 属性値
maxLengthmaxLength 属性値
minmin 属性値
minLengthminLength 属性値
patternpattern 属性値
placeholderplaceholder 属性値
readOnlyreadOnly 属性値
sizesize 属性値
stepstep 属性値
記述例
<form name="f1" action="#">
  <input type="text" name="e1" minlength="3" maxlength="5" autocomplete="on" size="6" value="初期値">
  <input type="tel" name="e2" pattern="^[0-9]{9,11}$" required="true" placeholder="0311112222">
  <input type="number" name="e3" min="0" max="100" step="1">
</form>

<div id="d1"></div>
<!-- 以下略 -->

<script>
let f = document.forms[0];
document.getElementById("d1").textContent=f.e1.minLength;
document.getElementById("d2").textContent=f.e1.maxLength;
document.getElementById("d3").textContent=f.e1.autocomplete;
document.getElementById("d4").textContent=f.e1.size;
document.getElementById("d5").textContent=f.e1.defaultValue;
document.getElementById("d6").textContent=f.e2.pattern;
document.getElementById("d7").textContent=f.e2.required;
document.getElementById("d8").textContent=f.e2.placeholder;
document.getElementById("d9").textContent=f.e3.min;
document.getElementById("d10").textContent=f.e3.max;
document.getElementById("d11").textContent=f.e3.step;

</script>
実行例

実行時に設定されるプロパティには次のものがあります。

プロパティ
selectionStart選択範囲の開始位置(0~)
selectionEnd選択範囲の終了位置の次の位置(selectionStart <= selectionEnd)
selectionDirection選択方向
意味
forward先頭から末尾の方向
backward末尾から先頭の方向
none不明
記述例
<form>
  <input type="text" name="e1" readonly="true" size="30" value="ABCDEFGHIJKLMNOPQRSTUVWXYZ">
</form>

<div id="d1"></div>
<!-- 以下略 -->

<script>
function set() {
  document.getElementById("d1").textContent=f.e1.selectionStart;
  document.getElementById("d2").textContent=f.e1.selectionEnd;
  document.getElementById("d3").textContent=f.e1.selectionDirection;
  document.getElementById("d4").textContent=f.e1.value;
  document.getElementById("d5").textContent=f.e1.defaultValue;
}
let f = document.forms[0];
f.e1.addEventListener("select", set);
f.e1.addEventListener("input", set);
</script>

文字列を選択してみてください。選択方向によって、selectionDirection 値が変わります。

また、value 値も表示しています。文字列を変更することによって、value 値が変わります。元々の値は defaultValue 値にあります。

実行例


○ type=checkbox、radio のプロパティ

type が checkbox や radio などである input 要素に適用される主なプロパティには次のようなものがあります。

プロパティ
checkedchecked 属性
defaultChecked操作する前の、元々の checked 属性値
記述例
<form name="f1" action="#">
  <input type="checkbox" name="e1" value="1" onclick="checkChecked(cb, 'd12')">選択1 
  <input type="checkbox" name="e1" value="2" onclick="checkChecked(cb, 'd12')" checked>選択2  <!-- checked -->
  <input type="checkbox" name="e1" value="3" onclick="checkChecked(cb, 'd12')">選択3 
  <span id="d11" style="background-color:yellow;"></span> <span id="d12"></span><br>
  <input type="radio" name="e2" value="1" onclick="checkChecked(rb, 'd22')">選択1 
  <input type="radio" name="e2" value="2" onclick="checkChecked(rb, 'd22')" checked>選択2     <!-- checked -->
  <input type="radio" name="e2" value="3" onclick="checkChecked(rb, 'd22')">選択3 
  <span id="d21" style="background-color:yellow;"></span> <span id="d22"></span>
</form>
<script>
var cb = document.f1.e1;
var rb = document.f1.e2;
function checkChecked(c, id) {
  let s = "";
  for (var i = 0 ; i < c.length ; i++) {
    if (c[i].checked == true)
      s += c[i].value + " ";
  }
  document.getElementById(id).textContent = s;
}
function checkDefaultChecked(c, id) {
  let s = "";
  for (var i = 0 ; i < c.length ; i++) {
    if (c[i].defaultChecked == true) {
      s += c[i].value + " ";
  }
  document.getElementById(id).textContent = s;
}
cb[2].checked = true;          // チェックボックスの「選択3」は、実行時にチェックを付けている
checkDefaultChecked(cb, "d11");
checkChecked(cb, "d12");
checkDefaultChecked(rb, "d21");
checkChecked(rb, "d22");
</script>

チェックボックスやラジオボタンにチェックを付けると、チェックのついた要素の value がその右側に表示されます。

背景が黄色い部分は 初期値として checked が付けられている要素です。なお、チェックボックスの「選択3」は、実行時にチェックを付けるため、背景が黄色い "3" は表示されません。

実行例


○ type=file のプロパティ

type が file である input 要素に適用される主なプロパティには次のようなものがあります。

プロパティ
acceptaccept 属性
multiplemultiple 属性
files選択されたファイルのリスト

multiple が指定されているので、複数ファイルを選択することができます。

<form name="f1">
  <input type="file" name="e1" accept="image/png,image/gif" multiple>
  <input type="button" value="送信" onclick="document.getElementById("d3").textContent=dispList(f.e1.files);">
</form>

<div id="d1"></div>
<div id="d2"></div>
<div id="d3"></div>

<script>
function dispList(list) {
  let s = "";
  for (let i = 0 ; i < list.length ; i++) {
    s += list[i].name + " ";
  }
  return s;
}
let f = document.forms[0];
document.getElementById("d1").textContent=f.e1.accept;
document.getElementById("d2").textContent=f.e1.files;
</script>

files は選択されたファイルのリストなので、ファイル選択後[送信]ボタンをクリックした後に表示されます。

実行例

○ type=image のプロパティ

type が image 要素に適用される主なプロパティには次のようなものがあります。

プロパティ
altalt 属性
heightheight 属性
srcsrc 属性
widthwidth 属性
記述例
<form>
  <input type="image" name="e1" src="bear3.png" alt="くま">
</form>
<div id="d1"></div>
<!-- 以下略 -->

<script>
let f = document.forms[0].children["e1"];    // document.forms[0].e1 は、なぜか undefined
document.getElementById("d1").textContent=e1.src;
document.getElementById("d2").textContent=e1.alt;
document.getElementById("d3").textContent=e1.height;
document.getElementById("d4").textContent=e1.width;
</script>

src 属性で記述したファイルがボタンのイメージになります。

表示例

(3) メソッド

エレメント.select()

入力フィールド内の文字列を選択状態にする。

戻り値:なし

記述例
<form name="f1" action="#">
  <input type="text" name="e1" value="初期値"> <input type="text" name="e2" placeholder="入力ヒント">
  <div onClick="document.f1.e1.select();">選択状態にする</div> <div onClick="document.f1.e2.select();">選択状態にする</div>
</form>

[選択状態にする]ボタンをクリックすると入力されている文字列が選択状態になります。右側は placeholder なので選択されず、未入力状態になります。

実行例

エレメント.setSelectionRange(開始, 終了[, 選択方向])

入力フィールド内の文字列を選択状態にする。

引数 開始:選択する最初の文字の位置(0~終了)

引数 終了:選択する最後の文字の次の位置(開始~)

引数 選択方向:選択が行われたと見なされる方向(有効かどうか不明)

主な特性機能
forward開始から終了方向
backward終了から開始方向
none選択方向が不明(規定値)

戻り値:なし

記述例
<form>
  <input type="text" name="e1" size="40" value="郵便局は、post office といいます。"><br>
  範囲:<input type="number" name="s" min="0" max="23" size="2" value="12"><input type="number" name="e" min="0" max="23" size="2" value="20"><br>
  選択方向:<select name="d"><br><br>
   <option value="forward" label="forward(開始から終了方向)"></option>
   <option value="backward" label="backward(終了から開始方向)"></option>
   <option value="none" selected label="none(選択方向が不明)"></option>
  </select><br><br>
  <div onClick="selectText();">選択</div>
</form>

<script>
function selectText() {
  let f = document.forms[0];
  let s = f.s.value;
  let e = f.e.value;
  let d = f.d.value;
  f.e1.focus();
  f.e1.setSelectionRange(s, +e+1, d);      // +e : 数値化
}
</script>

下の例の Office という文字列は ffi の部分が合字されて表示されています。しかし、setSelectionRange はそれらを f f i の3文字と正しく判断しているようです。(合字については、E::first-letterfont-variant-ligatures も参照してください。)

また、選択方向が有効かどうかはよくわかりません。

実行例

エレメント.setRangeText(挿入文字列[, 開始, 終了[, 選択モード]])

入力フィールド内の指定された範囲を挿入文字列で置換する。

引数 挿入文字列:挿入する文字列

引数 開始:置換する最初の文字の位置(0~)(規定値:選択されている範囲の開始位置)

引数 終了:置換する最後の文字の次の位置(0~)(規定値:選択されている範囲の終了位置)

引数 選択モード:置換後の選択範囲

主な特性機能
select新規挿入した文字列を選択
start挿入した文字列の直前を選択
end挿入した文字列の直後を選択
preserve選択範囲を保全(規定値)

戻り値:なし

記述例
<form>
  <input type="text" name="e1" size="40" value="郵便局は、post office といいます。"><br>
  範囲:<input type="number" name="s" min="0" max="23" size="2" value="12"><input type="number" name="e" min="0" max="23" size="2" value="20"><br>
  挿入文字列:<input type="text" name="r" size="11" maxlength="10"><br>
  選択モード:<select name="m"><br><br>
   <option value="select" label="select(挿入文字列を選択)"></option>
   <option value="start" label="start(挿入文字列の直前を選択)"></option>
   <option value="end" label="end(挿入文字列の直後を選択)"></option>
   <option value="preserve" selected label="preserve(選択範囲を保全)"></option>
  </select><br><br>
  <div onClick="replaceText();">置換</div>
</form>

<script>
function replaceText() {
  let f = document.forms[0];
  let s = f.s.value;
  let e = f.e.value;
  let r = f.r.value;
  let m = f.m.value;
  f.e1.focus();
  f.e1.setRangeText(r, s, +e+1, m, );      // +e : 数値化
}
</script>

入力されている文字列のどこかを選択した後に、置換してみてください。

選択モードが select のときは、挿入文字列が選択され、preserve のときは、置換前の選択領域が維持されます。

実行例
再実行



8.11.3  セレクト部品(HTMLSelectElement)

HTMLSelectElement オブジェクトは、select 要素を表します。

HTMLSelectElement は HTMLElement を継承していますので、HTMLElement のプロパティや機能を使用することができます。

Node Element HTMLElement HTMLSelectElement

(1) フォーム部品情報

プロパティ
formR/Oフォーム部品を包含するフォームオブジェクト(HTMLFormElement
autofocusautofocus 属性値
disableddisabled 属性値
namename 属性値
typeR/O セレクトタイプ
意味
select-one1つ(multiple 属性 = false)
select-multiple複数(multiple 属性 = true)
valuevalue 属性値
selectedIndex現在選択されているオプションを示すインデックス番号(0~)
multiplemultiple 属性
sizesize 属性
optionsR/Oオプションのリスト(HTMLOptionElement を持つ HTMLOptionsCollection)
HTMLOptionElement
プロパティ
option.defaultSelected操作する前の、元々のオプションの selected 属性値
option.disabledオプションの disabled 属性値
option.selected選択されているかどうか(true:選択されている、false:されていない)
option.labelR/Oオプションの label 属性
option.valueオプションの value 属性
記述例
<form name="f1">
  <select name="e1" autofocus="true">
    <option value="1" label="AAAAA"></option>
    <option value="2" label="BBBBB"></option>
    <option value="3" label="CCCCC" selected></option>
    <option value="4" label="DDDDD"></option>
  <select>
  <select name="e2" disabled multiple size="2">
    <option value="1" label="AAAAA" selected></option>
    <option value="2" label="BBBBB"></option>
    <option value="3" label="CCCCC" selected></option>
    <option value="4" label="DDDDD"></option>
  <select>
</form>
<span id="d11"></span> <span id="d12"></span><br>
<!-- 以下略 -->

<script>
function dispOptions(list) {
  let s = "";
  let d1 = "", d2 = "";
  for (let i = 0 ; i < list.length ; i++) {
    if (list[i].defaultSelected) {
      d1 = "<span style='background-color:yellow;'>";
      d2 = "</span>";
    }
    else {
      d1 = d2 = "";
    }
    s += d1 + list[i].label + "(" + list[i].value + ")" + d2 + "<br>";
  }
  return s;
}
let f = document.forms[0];
document.getElementById("d11").textContent=f.e1.tagName;
document.getElementById("d21").textContent=f.e1.type;
document.getElementById("d31").textContent=f.e1.value;
document.getElementById("d41").textContent=f.e1.name;
document.getElementById("d51").textContent=f.e1.autofocus;
document.getElementById("d61").textContent=f.e1.disabled;
document.getElementById("d71").textContent=f.e1.size;
document.getElementById("d81").innerHTML=dispOptions(f.e1.options);
document.getElementById("d91").textContent=f.e1.form.name;
document.getElementById("d12").textContent=f.e2.tagName;
document.getElementById("d22").textContent=f.e2.type;
document.getElementById("d32").textContent=f.e2.value;
document.getElementById("d42").textContent=f.e2.name;
document.getElementById("d52").textContent=f.e2.autofocus;
document.getElementById("d62").textContent=f.e2.disabled;
document.getElementById("d72").textContent=f.e2.size;
document.getElementById("d82").innerHTML=dispOptions(f.e2.options);
document.getElementById("d92").textContent=f.e2.form.name;
</script>

options は、label 属性(value 属性) を表示しています。また、defaultSelected 属性 が true のオプションの背景を黄色にしています。

form はオブジェクトが返るため、この例では form の name 属性を表示しています。

実行例



実行時に設定されるプロパティには次のものがあります。

プロパティ
selectedIndex現在選択されているオプションを示すインデックス番号(0~)
選択されていないときは -1
optionsオプションのリスト(HTMLOptionElement を持つ HTMLOptionsCollection)
HTMLOptionElement
プロパティ
option.selected選択されているかどうか(true:選択されている、false:されていない)
selectedOptions R/O選択されている option 要素のリスト(HTMLCollection)
記述例
<form name="f1">
  <select name="e1" onclick="dispSelectedIndex(this, 'd12');">
    <option value="1" label="AAAAA"></option>
    <option value="2" label="BBBBB"></option>
    <option value="3" label="CCCCC" selected></option>
    <option value="4" label="DDDDD"></option>
  </select>
  <span id="d11" style="background-color:yellow;"></span> <span id="d12"></span><br>
  <br>
  <select name="e2" multiple size="4"
      onclick="dispSelectedIndex(this, 'd22'); dispOptions(this, 'd23'); dispSelectedOptions(this, 'd24');">
    <option value="1" label="AAAAA"></option>
    <option value="2" label="BBBBB" selected></option>
    <option value="3" label="CCCCC"></option>
    <option value="4" label="DDDDD" selected></option>
  </select>
  <span id="d21" style="background-color:yellow;"></span> <span id="d22"></span> 
  <span id="d23"></span> <span id="d24"></span>
</form>
 
<script>
let e1 = document.f1.e1;
let e2 = document.f1.e2.list;

function dispSelectedIndex(c, id) {
  document.getElementById(id).textContent = c.selectedIndex;
}
function dispOptions(c, id) {
  let s = "";
  for (let i = 0 ; i < c.length ; i++) {
    if (c[i].selected == true)    // オプションのリスト(selected が true だと選択済)
      s += i + " ";
  }
  document.getElementById(id).textContent = s;
}
function dispSelectedOptions(c, id) {
  let s = "";
  let o = c.selectedOptions;    // 選択されているオプションのみのリスト
  for (let i = 0 ; i < o.length ; i++) {
    s += o[i].index + " ";
  }
  document.getElementById(id).textContent = s;
}
function getDefaultSelected(c) {
  let a = [];
  for (let i = 0 ; i < c.length ; i++) {
    if (c[i].defaultSelected == true)
      a = a.concat(i);
  }
  return a;
}
function checkDefaultSelected(c, id) {
  let a = getDefaultSelected(c);
  if (a != []) {
    let s = "";
    for (let i = 0 ; i < a.length ; i++) {
      s += a[i] + " ";
    document.getElementById(id).textContent = s;
  }
}
checkDefaultSelected(e1, "d11"); dispSelectedIndex(e1, "d12");
checkDefaultSelected(e2, "d21"); dispOptions(e2, "d22"); dispSelectedOptions(e2, "d23");
</script>

一つ目は選択肢を1つだけ、二つ目は複数選択できます(size='4' を指定して選択肢が4つとも表示されるようにしています)。

1つだけ選択できる場合は、selectedIndex に選択した要素のインデックスが設定されます。複数選択できる場合も同様に設定されますが、この場合に設定されるインデックスは選択されている要素の一番小さいインデックスになります。

複数選択の場合は、options 属性のうち、選択された選択肢のみ selected が true になります。また、selectedOptions には選択された options 属性のみのリストが設定されます。

背景が黄色い部分は 初期値として selected が付けられている要素です。

実行例

(2) メソッド

セレクト.add(要素[, 挿入位置])

select 要素の option 要素リストの指定位置に挿入する。

引数 要素:挿入する option 要素、または optgroup 要素

引数 挿入位置:挿入する位置(0~)または挿入したい位置にある要素(null は最後に追加) (規定値:null)

戻り値:なし


セレクト.remove(要素位置)

select 要素の option 要素リストから指定位置の要素を削除する。

引数 要素位置:削除する option 要素の位置(0~)

戻り値:なし


select 要素に option 要素を追加、select 要素から option 要素を削除します。

記述例
<form name="f1">
  <table>
    <tr><td>
    <select name="e1" size="5" style="width:100px;">
      <option value="AAAAA" label="AAAAA"></option>
      <option value="BBBBB" label="BBBBB"></option>
      <option value="CCCCC" label="CCCCC"></option>
      <option value="DDDDD" label="DDDDD"></option>
    </select>
    </td><td><input name="e2" type="text" size="10" maxlength="8" placeholder="追加文字列"></input><br><br>
    <input type="button" value="追加" onclick="append();"><br><br><input type="button" value="削除" onclick="remove();">
    </td></tr>
  </table>
</form>

<script>
var e1 = document.f1.e1;
var e2 = document.f1.e2;
function append() {
  if (e2.value != "") {
    let n = e1.selectedIndex >= 0 ? e1.selectedIndex : null;
    let o = document.createElement("option");
    o.value = e2.value;
    o.label = e2.value;
    e1.add(o, n);
  }
}
function remove() {
  if (e1.selectedIndex >= 0) {
    e2.value = e1.options[e1.selectedIndex].label;
    e1.remove(e1.selectedIndex);
  }
}
</script>

[追加]ボタンで右側の入力欄の文字列を左のリストの選択位置の前に挿入します。選択されていなければリストの最後に追加します。

[削除]ボタンで左のリストの選択位置を削除します。削除された要素のラベルは右側の入力欄に表示されます。

実行例
再実行




ただし、選択肢グループ (optgroup) に追加するためには、セレクトの add() ではなく、選択肢グループに appendChild()insertBefore() する必要があります。

記述例
<form name="f1">
  <table>
    <tr><td>
    <select name="e1" size="5" style="width:100px;">
      <optgroup label="XXX">
        <option value="AAAAA" label="AAAAA"></option>
        <option value="BBBBB" label="BBBBB"></option>
      </optgroup>
      <optgroup label="YYY">
        <option value="CCCCC" label="CCCCC"></option>
        <option value="DDDDD" label="DDDDD"></option>
      </optgroup>
    </select>
    </td><td><input name="e2" type="text" size="10" maxlength="8" placeholder="追加文字列"></input><br><br>
    <input type="button" value="追加" onclick="append();"><br><br><input type="button" value="削除" onclick="remove();">
    </td></tr>
  </table>
</form>

<script>
var e1 = document.f1.e1;
var e2 = document.f1.e2;
function append() {
  if (e2.value != "") {
    let r = e1.selectedIndex >= 0 ? e1.options[e1.selectedIndex] : null;
    let n = e1.selectedIndex >= 0 ? e1.selectedIndex : e1.options.length - 1;
    let o = document.createElement("option");
    o.value = e2.value;
    o.label = e2.value;
    e1.options[n].parentElement.insertBefore(o, r); // 選択したオプションの属するグループに追加
  }
}
function remove() {
  if (e1.selectedIndex >= 0) {
    e2.value = e1.options[e1.selectedIndex].label;
    e1.remove(e1.selectedIndex);
  }
}
</script>

次の例では、insertBefore() しか使用していないため、最後の選択肢グループではないグループ(次の例では XXX)の最後に追加できるようにはなっていません。

実行例
再実行





移動先の select 要素に、移動元 select 要素の option を add すると、移動元 select 要素の option が削除されるようです。

記述例
<form name="f1">
  <table>
    <tr><td>
    <select name="e1" multiple size="5" style="width:100px;">
      <option value="AAAAA" label="AAAAA"></option>
      <option value="BBBBB" label="BBBBB"></option>
      <option value="CCCCC" label="CCCCC" selected></option>
      <option value="DDDDD" label="DDDDD"></option>
    </select>
    </td><td>
    <input type="button" value="→" onclick="moveRight();">&nbsp;&nbsp;&nbsp;<input type="button" value="←" onclick="moveLeft();">
    </td><td>
    <select name="e2" multiple size="5" style="width:100px;">
    </select>
    </td></tr>
  </table>
</form>

<script>
var e1 = document.f1.e1;
var e2 = document.f1.e2;
function moveRight() {
  if (e1.selectedIndex >= 0) {
    let n = e2.selectedIndex >= 0 ? e2.selectedIndex : null;
    while (e1.selectedOptions.length > 0) {
      e2.add(e1.selectedOptions[e1.selectedOptions.length - 1], n);
      if (n == null)
        n = e2.options.length - 1;
    }
  }
}
function moveLeft() {
  if (e2.selectedIndex >= 0) {
    let n = e1.selectedIndex >= 0 ? e1.selectedIndex : null;
    for (let i = e2.options.length - 1 ; i >= 0 ; i--) {
      if (e2.options[i].selected) {
        e1.add(e2.options[i], n);
        if (n == null)
          n = e1.options.length - 1;
      }
    }
  }
}
</script>

次の例でも、移動元 select 要素の option を remove しなくても削除されています。

移動元の要素を選択して、[→][←]ボタンをクリックして、リスト間で要素の移動をします。

実行例
再実行



8.11.4  複数行テキスト部品(HTMLTextAreaElement)

HTMLTextAreaElement オブジェクトは、textarea 要素を表します。

HTMLTextAreaElement は HTMLElement を継承していますので、HTMLElement のプロパティや機能を使用することができます。

Node Element HTMLElement HTMLTextAreaElement

(1) フォーム部品情報

プロパティ
formR/Oフォーム部品を包含するフォームオブジェクト(HTMLFormElement
autofocusautofocus 属性値
colscols 属性値
defaultValue初期文字列
disableddisabled 属性値
maxLengthmaxlength 属性(入力最大文字数)
minLengthminLength 属性(入力最小文字数)
namename 属性値
placeholderplaceholder 属性値
readOnlyreadonly 属性値
requiredrequired 属性値
rowsrows 属性値
wrapwrap 属性値(送信時の改行の有無)
意味
soft折り返し部分に改行が入らない
hard折り返し部分に改行が入る
value不明
記述例
<form name="f1">
  <textarea name="e1" disabled readOnly="true" wrap="soft">書き込み禁止</textarea>
  <textarea name="e2" placeholder="こちらから入力" rows="5" cols="50"
                      maxLength="100" minLength="5" wrap="hard" required autofocus="true"></textarea>
</form>
<span id="d11"></span> <span id="d12"></span><br>
<!-- 以下略 -->

<script>
let f = document.forms[0];
document.getElementById("d11").textContent=f.e1.tagName;
document.getElementById("d21").textContent=f.e1.defaultValue;
document.getElementById("d31").textContent=f.e1.name;
document.getElementById("d41").textContent=f.e1.rows;
document.getElementById("d51").textContent=f.e1.cols;
document.getElementById("d61").textContent=f.e1.maxLength;
document.getElementById("d71").textContent=f.e1.minLength;
document.getElementById("d101").textContent=f.e1.autofocus;
document.getElementById("d111").textContent=f.e1.disabled;
document.getElementById("d121").textContent=f.e1.readOnly;
document.getElementById("d131").textContent=f.e1.required;
document.getElementById("d141").textContent=f.e1.wrap;
document.getElementById("d151").textContent=f.e1.form.name;

document.getElementById("d12").textContent=f.e2.tagName;
<!-- 途中略 -->
document.getElementById("d152").textContent=f.e2.form.name;

</script>

form はオブジェクトが返るため、この例では form の name 属性を表示しています。

実行例

実行時に設定されるプロパティには次のものがあります。

プロパティ
selectionStart選択した文字列の開始位置(0~)
selectionEnd選択した文字列の終了位置の次の位置(selectionStart <= selectionEnd)
selectionDirection選択方向
意味
forward先頭から末尾の方向
backward末尾から先頭の方向
none不明
value入力文字列
textLength入力文字列長R/O

記述例
<form name="f1">
  <textarea name="e1" rows="3" cols="10" maxLength="30" minLength="5">ABCDEFGHIJKLMNOPQRST</textarea>
</form>

<div id="d1"></div>
<!-- 以下略 -->

<script>
function set() {
  document.getElementById("d1").textContent=f.e1.selectionStart;
  document.getElementById("d2").textContent=f.e1.selectionEnd;
  document.getElementById("d3").textContent=f.e1.selectionDirection;
  document.getElementById("d4").textContent=f.e1.value;
  document.getElementById("d5").textContent=f.e1.textLength;
  document.getElementById("d6").textContent=f.e1.defaultValue;
}
let f = document.forms[0];
f.e1.addEventListener("select", set);
f.e1.addEventListener("input", set);
</script>

文字列を選択してみてください。選択方向によって、selectionDirection 値が変わります。

また、value 値も表示しています。文字列を変更することによって、value 値が変わります。元々の値は defaultValue 値にあります。

実行例

(2) メソッド

エレメント.select()

入力フィールド内の文字列を選択状態にする。

戻り値:なし

記述例
<form name="f1" action="#">
  <textarea name="e1" rows="2" cols="10">初期値</textarea> 
  <textarea name="e2" rows="2" cols="10" placeholder="入力ヒント"></textarea>
  <div onClick="document.f1.e1.select();">選択状態にする</div> <div onClick="document.f1.e2.select();">選択状態にする</div>
</form>

[選択状態にする]ボタンをクリックすると入力されている文字列が選択状態になります。右側は placeholder なので選択されず、未入力状態になります。

実行例

エレメント.setSelectionRange(開始, 終了[, 選択方向])

入力フィールド内の文字列を選択状態にする。

引数 開始:選択する最初の文字の位置(0~終了)

引数 終了:選択する最後の文字の次の位置(開始~)

引数 選択方向:選択が行われたと見なされる方向(有効かどうか不明)

主な特性機能
forward開始から終了方向
backward終了から開始方向
none選択方向が不明(規定値)

戻り値:なし

記述例
<form>
  <textarea name="e1" rows="2" cols="20">郵便局は、post office といいます。</textarea><br>
  範囲:<input type="number" name="s" min="0" max="23" size="2" value="12"><input type="number" name="e" min="0" max="23" size="2" value="20"><br>
  選択方向:<select name="d"><br><br>
   <option value="forward" label="forward(開始から終了方向)"></option>
   <option value="backward" label="backward(終了から開始方向)"></option>
   <option value="none" selected label="none(選択方向が不明)"></option>
  </select><br><br>
  <div onClick="selectText();">選択</div>
</form>

<script>
function selectText() {
  let f = document.forms[0];
  let s = f.s.value;
  let e = f.e.value;
  let d = f.d.value;
  f.e1.focus();
  f.e1.setSelectionRange(s, +e+1, d);      // +e : 数値化
}
</script>

下の例の Office という文字列は ffi の部分が合字されて表示されています。しかし、setSelectionRange はそれらを f f i の3文字と正しく判断しているようです。(合字については、E::first-letterfont-variant-ligatures も参照してください。)

また、選択方向が有効かどうかはよくわかりません。

実行例

エレメント.setRangeText(挿入文字列[, 開始, 終了[, 選択モード]])

入力フィールド内の指定された範囲を挿入文字列で置換する。

引数 挿入文字列:挿入する文字列

引数 開始:置換する最初の文字の位置(0~)(規定値:選択されている範囲の開始位置)

引数 終了:置換する最後の文字の次の位置(0~)(規定値:選択されている範囲の終了位置)

引数 選択モード:置換後の選択範囲

主な特性機能
select新規挿入した文字列を選択
start挿入した文字列の直前を選択
end挿入した文字列の直後を選択
preserve選択範囲を保全(規定値)

戻り値:なし

記述例
<form>
  <textarea name="e1" rows="2" cols="20">郵便局は、post office といいます。</textarea><br>
  範囲:<input type="number" name="s" min="0" max="23" size="2" value="12"><input type="number" name="e" min="0" max="23" size="2" value="20"><br>
  挿入文字列:<input type="text" name="r" size="11" maxlength="10"><br>
  選択モード:<select name="m"><br><br>
   <option value="select" label="select(挿入文字列を選択)"></option>
   <option value="start" label="start(挿入文字列の直前を選択)"></option>
   <option value="end" label="end(挿入文字列の直後を選択)"></option>
   <option value="preserve" selected label="preserve(選択範囲を保全)"></option>
  </select><br><br>
  <div onClick="replaceText();">置換</div>
</form>

<script>
function replaceText() {
  let f = document.forms[0];
  let s = f.s.value;
  let e = f.e.value;
  let r = f.r.value;
  let m = f.m.value;
  f.e1.focus();
  f.e1.setRangeText(r, s, +e+1, m, );      // +e : 数値化
}
</script>

入力されている文字列のどこかを選択した後に、置換してみてください。

選択モードが select のときは、挿入文字列が選択され、preserve のときは、置換前の選択領域が維持されます。

実行例
再実行



8.12   イメージ(HTMLImageElement)

document の images プロパティでイメージ要素(HTMLImageElement)のリストを得ることができます。

Node Element HTMLElement HTMLImageElement

各イメージ要素は、リストの要素番号を指定し、

  let img = document.images[0];    // 最初の image 要素

のように参照することができます。また、イメージ要素の id 属性があれば id で参照することもできます。

  let img = document.img1;          // <img id="img1" ...
  let img = document.images["img1"];

イメージ要素の主なプロパティとメソッドについて説明します。

8.12.1   イメージ要素

プロパティ
altalt 属性値(画像を表示しない場合の代替文字列)
completeR/O読込みが完了しているかどうか(true:完了、false:未完)
読み込めなくても読み込めないと分かった時点で true になる。
height画像の表示上の高さ
isMapR/Oサーバサイドイメージマップを使用するかどうか(true:使用する、false:使用しない)
naturalHeightR/O画像の本来の高さ
naturalWidthR/O画像の本来の幅
srcsrc 属性値(画像ファイルの URL)
useMapR/Oクライアントサイドイメージマップの要素名
width画像の表示上の幅
xR/O画像の表示された横位置
yR/O画像の表示された縦位置
記述例
<img id="e1" src="figures/bear.png" alt="右手(?)を挙げた熊" width="56" height="111" usemap="#fist">
<map name="fist">
  <area shape="circle" coords="13,39,11" href="#" title="こぶし">
</map>
<div id="d1"></div>
<!-- 以下略 -->

<script>
let i = document.images;
document.getElementById('d1').textContent=i.e1.alt;
document.getElementById('d2').textContent=i.e1.width;
document.getElementById('d3').textContent=i.e1.height;
document.getElementById('d4').textContent=i.e1.naturalWidth;
document.getElementById('d5').textContent=i.e1.naturalHeight;
document.getElementById('d6').textContent=i.e1.src;
document.getElementById('d7').textContent=i.e1.x;
document.getElementById('d8').textContent=i.e1.y;
document.getElementById('d9').textContent=i.e1.ismap;
document.getElementById('d10').textContent=i.e1.usemap;
</script>

74 × 74 のサイズの画像を拡縮して表示しています。また、ismap は指定していませんが、usemap は使用しています。

実行例

なお、width や height を変更すれば、画像の大きさを変えることができます。

記述例
<table>
 <tr><td style="height:160px;text-align:center;">
  <img id="e" src="figures/bear.png" width="74" height="74">
 </td><td style="width:20px;">
  <input type="range" name="h" min="0" max="148" value="74" style="width:148px;transform:rotateZ(90deg) translateY(70px);"
 onchange="document.getElementById('e').height=this.value;"><br>
 </td></tr>
 <tr><td>
  <input type="range" name="w" min="0" max="148" value="74" style="width:148px;height:10px;"
 onchange="document.getElementById('e').width=this.value;">
 </td><td></td></tr>
</table>
実行例

8.12.2  Image オブジェクト

Image オブジェクトでは、new 演算子を使って画像をオブジェクト化できます。

new Image([width, height])

Image インスタンスを生成する。

引数 width:画像の幅

引数 height:画像の高さ

戻り値:Image インスタンス

記述例
<body>
  <script>
  let img = new Image();
  img.src = "bear.png";
  document.body.appendChild(img);
  </script>
</body>
実行例

8.13   アンカー(HTMLAnchorElement)

document の links プロパティは、文書中の、 href 属性の値を持つすべての a 要素と area 要素のリストを返します。

Node Element HTMLElement HTMLAnchorElement

各リンク要素は、リストの要素番号を指定し、

  let lnk = document.links[0];    // 最初の a あるいは area要素

のように参照することができます。

ただし、document の links プロパティは a 要素の他に area 要素も含めたリストなので、アンカーオブジェクトのみを取り出す必要があります。

(1) アンカー情報

アンカーオブジェクトには、a 要素の情報が設定されています。

プロパティ
hash参照する URL の '#' を含むフラグメント識別子
hostサーバー名(href のホスト名)とポート番号
hostnameサーバー名(href のホスト名)
href新しく表示する文書や場所の URL
media対象とするメディアタイプ
originR/OURL のオリジン
passwordドメイン名の前で指定されたパスワード
pathnameパス名(href のホスト名より後の文字列)
portもしあればポート番号(href のポート番号)
protocolプロトコル(href の ':' 以前の文字列)
rel外部ファイルとの関係性 リンクタイプ
search'?' とその後に続く URL の引数
targetリンク先の内容を表示するウィンドウ(フレーム)名
typeリンク先の MIME タイプ
usernameドメイン名の前で指定されたユーザー名
記述例
<a id="a1" href="https://uname:pwd@wasika.noor.jp:80/bear.htm#fist" target="_self" type="text/html" rel="next">次の文書</a> 
<a id="a2" href="https://wasika.noor.jp/figures/bear.png?act=m;tm=3" target="ref" type="image/png" rel="nofollow">参考画像</a>
<map name="map">
  <area shape="circle" coords="17,26,11" href="circle.htm" title="まる"> 
</map>
<span id="d001"></span> <span id="d101"></span><br>
<!-- 以下略 -->

<script>
let lnk = document.links;
let n = 0;
for (let i = 0 ; i < lnk.length ; i++) {
  if (!(lnk[i] instanceof HTMLAnchorElement))
    continue;          // アンカー以外は表示しない
  document.getElementById("d" + n + "01").textContent=lnk[i].href;
  document.getElementById("d" + n + "02").textContent=lnk[i].protocol;
  document.getElementById("d" + n + "03").textContent=lnk[i].origin;
  document.getElementById("d" + n + "04").textContent=lnk[i].host;
  document.getElementById("d" + n + "05").textContent=lnk[i].hostname;
  document.getElementById("d" + n + "06").textContent=lnk[i].port;
  document.getElementById("d" + n + "07").textContent=lnk[i].pathname;
  document.getElementById("d" + n + "08").textContent=lnk[i].search;
  document.getElementById("d" + n + "09").textContent=lnk[i].type;
  document.getElementById("d" + n + "10").textContent=lnk[i].target;
  document.getElementById("d" + n + "11").textContent=lnk[i].rel;
  document.getElementById("d" + n + "12").textContent=lnk[i].hash;
  document.getElementById("d" + n + "13").textContent=lnk[i].username;
  document.getElementById("d" + n + "14").textContent=lnk[i].password;
  document.getElementById("d" + n + "15").textContent=lnk[i].text;
  n++;
}
</script>
実行例

8.14   エリア(HTMLAreaElement)

document の links プロパティは、文書中の、 href 属性の値を持つすべての area 要素と a 要素のリストを返します。

Node Element HTMLElement HTMLAreaElement

各リンク要素は、リストの要素番号を指定し、

  let lnk = document.links[0];    // 最初の area あるいは a 要素

のように参照することができます。

ただし、document の links プロパティは area 要素の他に a 要素も含めたリストなので、エリアオブジェクトのみを取り出す必要があります。

(1) エリア情報

エリアオブジェクトには、area 要素の情報が設定されています。

document の links プロパティは area 要素の他に a 要素も含めたリストなので、エリアオブジェクトのみを取り出す必要があります。

プロパティ
coords領域の座標(x,y)等
hash参照する URL の '#' を含むフラグメント識別子
hostサーバー名(href のホスト名)とポート番号
hostnameサーバー名(href のホスト名)
href新しく表示する文書や場所の URL
media対象とするメディアタイプ
originR/OURL のオリジン
pathnameパス名(href のホスト名より後の文字列)
portもしあればポート番号(href のポート番号)
protocolプロトコル(href の ':' 以前の文字列)
rel外部ファイルとの関係性 リンクタイプ
search'?' とその後に続く URL の引数
shape領域の形状
targetリンク先の内容を表示するウィンドウ(フレーム)名
記述例
<img id="e1" src="bear.png" title="右手(?)を挙げた熊" width="74" height="74" usemap="#map"> 
<a id="a1" href="bear.htm">くま</a> 
<map name="map">
  <area shape="circle" coords="17,26,11" href="https://uname:pwd@wasika.noor.jp:80/fist.htm#fist" target="_self" rel="next" title="こぶし"> 
  <area shape="circle" coords="46,25,5" title="はな"> 
  <area shape="default" coords="0,0,73,73" href="https://wasika.noor.jp/other.htm?act=m;tm=3" title="その他" target="other"> 
</map>
<span id="d001"></span> <span id="d101"></span><br>
<!-- 以下略 -->

<script>
let lnk = document.links;
let n = 0;
for (var i = 0 ; i < lnk.length ; i++) {
  if (!(lnk[i] instanceof HTMLAreaElement))
    continue;          // エリア以外は表示しない
  document.getElementById("d" + n + "01").textContent=lnk[i].href;
  document.getElementById("d" + n + "02").textContent=lnk[i].alt;
  document.getElementById("d" + n + "03").textContent=lnk[i].shape;
  document.getElementById("d" + n + "04").textContent=lnk[i].coords;
  document.getElementById("d" + n + "05").textContent=lnk[i].host;
  document.getElementById("d" + n + "06").textContent=lnk[i].hostname;
  document.getElementById("d" + n + "07").textContent=lnk[i].port;
  document.getElementById("d" + n + "08").textContent=lnk[i].pathname;
  document.getElementById("d" + n + "09").textContent=lnk[i].hash;
  document.getElementById("d" + n + "10").textContent=lnk[i].search;
  document.getElementById("d" + n + "11").textContent=lnk[i].target;
  document.getElementById("d" + n + "12").textContent=lnk[i].rel;
  document.getElementById("d" + n + "13").textContent=lnk[i].username;
  document.getElementById("d" + n + "14").textContent=lnk[i].password;
  document.getElementById("d" + n + "15").textContent=lnk[i].shape;
  n++;
}
</script>

二つ目の area 要素(はな)には href 属性がありません。この場合はエリアオブジェクトも生成されないようです。

実行例

8.15   メディア(HTMLMediaElement)

video 要素や audio 要素は、それぞれ HTMLVideoElement や HTMLAudioElement というオブジェクトです。

それらのオブジェクトは共に HTMLMediaElement を継承しています。また、HTMLMediaElement は HTMLElement を継承しています。

Node Element HTMLElement HTMLMediaElement HTMLVideoElement HTMLAudioElement

video 要素や audio 要素の getElementById メソッドなどで、それぞれ HTMLVideoElement や HTMLAudioElement というオブジェクトを得ることができます。

  let media = document.getElementById("xxx");    // video や audio要素

8.15.1  メディア情報

プロパティ
audioTracks音声トラック情報××××××
autoplay自動再生するかどうか(preload が 'none' でも自動再生する)(規定値:false)
bufferedR/Oバッファされたメディアデータの範囲
controller要素に割り当てられた MediaController オブジェクト(割り当てられていない場合の値は null)××××××
controls再生をコントロールするユーザインタフェースの表示(true:表示、false:非表示)を設定あるいは取得する。
crossOriginメディア要素の CORS 設定××××××
currentSrcR/Oメディアリソースの URI×××××
currentTime現在の再生時間
defaultMuted標準状態で音声がミュートされているかどうか(true:ミュートされている、false:されていない)(規定値:false)
defaultPlaybackRate標準の再生速度倍率(規定値:1)
durationR/Oメディアの長さ(秒)
endedR/O再生が終了しているかどうか(true:終了、false:途中)(規定値:false)
errorR/O一番最後に起きたエラー(エラーが起きていない場合は null)
loop繰り返し再生の有効、無効(true:有効、false:無効)(規定値:false)
mutedミュートされているかどうか(true:ミュートされている、false:されていない)(規定値:false)
networkStateR/O読込みでのネットワーク状況
名称説明
NETWORK_EMPTY0要素はまだ初期化されておらず、すべての属性は初期状態にある
NETWORK_IDLE1リソースは選択されているが、この時点ではネットワークを使用していない
NETWORK_LOADING2データのローディング中
NETWORK_NO_SOURCE3まだ利用するリソースが見つかっていない
pausedR/Oポーズ(一時停止)しているかどうか(true:ポーズしている、false:していない)(規定値:false)
playbackRate現在の再生速度倍率(規定値:1)
playedR/O再生中の情報を持つ TimeRanges オブジェクト
preloadメディアリソースをあらかじめ読み込むかどうか(規定値:auto)
名称説明
'none'事前に読み込みを行わない
'metadata'メタデータのみを事前ロードする
'auto'すべてのデータを事前に読み込む
×
readyStateR/O読み込み状況
名称説明
HAVE_NOTHING0メタ情報さえまだ取得していない
HAVE_METADATA1メタ情報は取得したが、動画本体のデータは充分に取得していない
HAVE_CURRENT_DATA2現時点での再生に必要な分は取得している
HAVE_FUTURE_DATA3現時点での再生だけでなく、後の再生に必要な分も完全ではないものの取得している
HAVE_ENOUGH_DATA4再生に必要なデータは、全て取得した
seekableR/O再生位置の変更可能な範囲の情報を持つ TimeRanges オブジェクト
seekingR/O再生位置を変更したかどうか(true:変更した、false:していない)(規定値:false)
srcメディアリソースファイル××××××
volume音量(0.0 (無音) ~ 1.0 (最大) )(規定値:1)

表示例では video と audio を切り替えるようになっていますが、記述例は video のみの対応になっています。

記述例
<span id="d01"></span><span id="d21"></span><br>
<!-- 以下略 -->

<video id="v" controls width="320" height="180">
  <source src="criticalCat.ogv" type='video/ogg; codecs="theora, vorbis"'>
  <source src="criticalCat.mp4" type='video/mp4; codecs="avc1.42E01E, mp4a.40.2"'>
</video>
<span id="d1"></span><br>
<span id="d2"></span><br>
<span id="d3"></span><br>
<span id="d4"></span>
        <input id="controls" type="checkbox" onchange="m.controls=set('d4',this.checked);"><br>
<span id="d5"></span>
        <input id="loop" type="checkbox" onchange="m.loop=set('d5',this.checked);"><br>
<span id="d6"></span>
        <input id="muted" type="checkbox" onchange="m.muted=set('d6',this.checked);"><br>
<span id="d7"></span>
        <input id="volume" type="range" min="0" max="1" step="0.1" value="1"
                onchange="m.volume=set('d7',this.value);"><br>
<span id="d8"></span><br>
<span id="d9"></span><br>

<script>
var m = document.getElementById("v");
function set(id, value) {
  document.getElementById(id).textContent = value;
  return value;
}
function dispInit(event) {
  document.getElementById("d01").textContent=m.src;
  document.getElementById("d02").textContent=m.currentSrc;
  document.getElementById("d03").textContent=m.autoplay;
  document.getElementById("d04").textContent=m.preload;
  document.getElementById("d05").textContent=m.defaultPlaybackRate;
  document.getElementById("d06").textContent=m.defaultMuted;
  document.getElementById("d07").textContent=m.crossOrigin==undefined?"undefined":m.crossOrigin;
  document.getElementById("d08").textContent=m.controller==undefined?"undefined":m.controller;
}
function dispEvent(event) {
  document.getElementById("d1").textContent=m.ended;
  document.getElementById("d2").textContent=m.currentTime;
  document.getElementById("d3").textContent=m.playbackRate;
  document.getElementById("d4").textContent=m.controls;controls.checked=m.controls;
  document.getElementById("d5").textContent=m.loop;loop.checked=m.loop;
  document.getElementById("d6").textContent=m.muted;muted.checked=m.muted;
  document.getElementById("d7").textContent=m.volume;volume.value=m.volume;
  document.getElementById("d8").textContent=m.paused;
  document.getElementById("d9").textContent=m.seeking;
  document.getElementById("d10").textContent=m.readyState;
  document.getElementById("d11").textContent=m.networkState;

  document.getElementById("d21").textContent=(m.audioTracks==undefined || m.audioTracks.length==0)?"undefined":m.audioTracks[0].id;
  document.getElementById("d22").textContent=m.duration;
  document.getElementById("d23").textContent=m.buffered.length==0?"":(m.buffered.start(0) + " ~ " + m.buffered.end(0));
  document.getElementById("d24").textContent=m.played.length==0?"":(m.played.start(0) + " ~ " + m.played.end(0));
  document.getElementById("d25").textContent=m.seekable.length==0?"":(m.seekable.start(0) + " ~ " + m.seekable.end(0));
}

dispInit();
m.addEventListener('timeupdate', dispEvent, false);
m.loop = true;
</script>

video あるいは audio を再生してみてください。

この例の video では source 要素でメディアリソースファイルを指定していますので、src には何も表示されません(video 要素の src 属性を指定していない)。

表示例

8.15.2  メディア操作

(1) メディア判定

メディアタイプが再生可能かどうかを判定します。

メディアオブジェクト.canPlayType(mediaType)

メディアタイプが再生可能かどうかを判定する。

引数 mediaType:メディアの MIME タイプ

 戻り値

'probably'再生可能
'maybe'おそらく再生可能(確実に再生できるとは言い切れない)
''再生不可能
記述例
<video id="v" width="10" height="10"></video>
<audio id="a"></audio>
<span id="d11"></span><span id="d21"></span><br>
<!-- 以下略 -->

<script>
var v = document.getElementById("v");
document.getElementById("d11").textContent=v.canPlayType("video/mp4");
document.getElementById("d12").textContent=v.canPlayType("video/webm");
document.getElementById("d13").textContent=v.canPlayType("video/ogg");
document.getElementById("d14").textContent=v.canPlayType("video/xxx");     // 不正 MIME
var a = document.getElementById("a");
document.getElementById("d21").textContent=a.canPlayType("audio/mp3");
document.getElementById("d22").textContent=a.canPlayType("audio/ogg");
document.getElementById("d23").textContent=a.canPlayType("audio/aac");
document.getElementById("d24").textContent=a.canPlayType("audio/xxx");     // 不正 MIME
</script>

どれが probably や maybe になるかは、ブラウザやプラグインの状況で変わります。また、再生不可能という判定になっても、実際には再生できる場合もあります。

動画 (video)音声 (audio) も参照してください。

表示例

(2) メディア再生

再生を開始したり、一時停止します。

メディアオブジェクト.play()

メディア再生を開始する。

引数 :なし

戻り値:なし

メディアオブジェクト.pause()

メディア再生を一時停止する。

引数 :なし

戻り値:なし

記述例
<video id="v" width="160" height="100"></video>
<source src="xxxxx.ogv" type='video/ogg; codecs="theora, vorbis"'>
<source src="xxxxx.mp4" type='video/mp4; codecs="avc1.42E01E, mp4a.40.2"'>
</video><br>
<div id="s" class="switch" onclick="play();">再生</div>
<script>
var v = document.getElementById("v");
var s = document.getElementById("s");
var pause = true;
v.addEventListener('ended', play, false);
function play() {
  if (pause == true) {
    pause = false;
    s.textContent = "一時停止";
    v.play();
  }
  else {
    pause = true;
    s.textContent = "再生";
    v.pause();
  }
}
</script>
表示例

(3) メディア・リソースのロード

src 属性に指定されたメディアを読み込みます。

preload が 'none' の場合は src 属性でメディア・リソースを指定しただけでは読み込まれませんので、load する必要があります。ただし、play を実行すれば読み込まれますので、再生する場合には特に必要ないかもしれません。また、autoplay 属性が指定されているも読み込まれます。

メディアオブジェクト.load()

メディア・リソースをロードする。

引数 :なし

戻り値:なし

記述例
<video id="v" src="xxxxx1.mp4" width="160" height="100" preload="none" autoplay></video>
<select name="file" onchange="set(this);">
<option value="xxxxx1" label="ねこ1"></option>
<option value="xxxxx2" label="ねこ2"></option>
<option value="xxxxx3" label="ねこ3"></option>
</select>
<br>
<div id="s" class="switch" onclick="play();">再生</div>
<script>
var v = document.getElementById("v");
var s = document.getElementById("s");
var pause = true;
var ext = ".mp4";
v.addEventListener('ended', play, false);
function play() {
  if (pause == true) {
    pause = false;
    s.textContent = "一時停止";
    v.play();
  }
  else {
    pause = true;
    s.textContent = "再生";
    v.pause();
  }
}
function set(c) {
  v.src = c[c.selectedIndex].value + ext;
  v.load();
  pause = true;
  play();
}
</script>

「ねこ1」「ねこ2」「ねこ3」を選択すると、対応する動画が再生されます。

表示例