HTML Living Standard  第3部 Javascript 13 jQuery


 

13 jQuery

jQuery(ジェイクエリー)は、JavaScript と HTML の相互作用を強化する軽量な JavaScript のライブラリです。ジョン・レシグが2006年1月に開催された BarCamp NYC でリリースしました。MIT LicenseGNU General Public License のデュアルライセンスであり、フリーかつオープンソースです。現在では様々な場面で活用されており、Javascript ライブラリのデファクトスタンダードと呼ばれることもあります。

jQuery を使用すれば、複雑になりがちな Javascript のコードをたくさん書かなくても、少ないコードで Javascript を実行できるようになる、と言うわけです。

ただし、最近の Javascript では jQuery を代替する機能が多く追加されています。したがって、jQuery を使用しなくても同様なことが比較的簡単に記述できるようになっています。よって、ここでは jQuery を使用しない記述も合わせて載せています。ただし、全く同じ機能を再現しているとは限りません。jQuery でなくても同じようなことができるという例です。jQuery は使いたくないけれど、この機能だけは使いたいというような場合に参考にしてください。


jQuery のバージョンは次のように、jquery というプロパティで取得できます。

プロパティ
jqueryR/OjQueryのバージョンナンバー
記述例
<span id="d1"></span><br>
<script>
var ver = $().jquery;         // バージョンを取得する
d1.textContent = ver;
</script>
実行例

13.1  基本的な使い方

13.1.1  jQuery の種類

jQuery のページ(http://jquery.com/download/)には、次の4種類のリンクがあります。

圧縮(compress)/非圧縮版(uncompress)版は、オリジナルのソースコードから改行や空白/コメントなどを除去しているかどうかの違いです。

○ Download the compressed, production jQuery 3.2.1
ファイル(jquery-3.2.1.min.js)は下のように、改行もスペースもインデントもなく、変数名なども一文字にするなど、余計なものを省くことで軽量化しています。
/*! jQuery v3.2.1 | (c) JS Foundation and other contributors | jquery.org/license */
!function(a,b){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0)function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){"use strict";var c=[],d=a.document,e=Object.getPrototypeOf,f=c.slice,g=c.concat,h=c.push,i=c.indexOf,j={},k=j.toString,l=j.hasOwnProperty,m=l.toString,n=m.call(Object),o=

// 以下略
    
ダウンロードサイズと実行速度のバランスから、通常リリースされるサービスで使うには最も適したものになります。

○ Download the uncompressed, development jQuery 3.2.1
ファイル(jquery-3.2.1.js)は下のように、改行もスペースもインデントも入っています。
/*!
 * jQuery JavaScript Library v3.2.1
 * https://jquery.com/
 
  中略 
 
 */
( function( global, factory ) {

  "use strict";

  if ( typeof module === "object" && typeof module.exports === "object" ) {

// 以下略
整形された、読み易い形のコードです。当然ながら、ファイルサイズは最も大きくなります。jQuery の中身の処理を読み解きたい場合などは、これを参考にするのが良いでしょう。

スリム版は jQuery 3 で新たに提供されました。Ajax、エフェクトなどの機能、非推奨機能を除去しており、より軽量になっているのが特徴です。

○ Download the compressed, production jQuery 3.2.1 slim build
ファイル(jquery-3.2.1.slim.min.js)は、Ajax、エフェクトなどの機能、非推奨機能を除去し、改行もスペースもインデントも削除したものになります。
○ Download the uncompressed, development jQuery 3.2.1 slim build
ファイル(jquery-3.2.1.slim.js)は、Ajax、エフェクトなどの機能、非推奨機能は除去されていますが、整形された、読み易い形のコードです。

13.1.2  jQuery の利用

jQuery ライブラリを利用するためには、ダウンロードしたファイルを script 要素で指定します。

<script src="jquery-3.2.1.min.js"></script>  ← ダウンロードした jQuery ライブラリ
<script>
  // jQuery を利用する関数など
</script>

ダウンロードしたファイルを指定する代わりに jQuery のサイトを直接参照することもできます。この方法だとバージョンアップのときなどその都度ダウンロードする必要はなくなりますが、ダウンロードしたファイルを読み込むのに比べると、読み込みにかかる時間は多くなります。

<script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>

13.1.3  jQuery オブジェクトの生成

jQuery では、操作する対象のことを jQuery オブジェクト(一般的なオブジェクト指向言語ではインスタンス)と呼びます。

jQuery のいろいろな機能は、この jQuery オブジェクトのメソッドとして提供されています。したがって、jQuery を利用するためには、まずこの jQuery オブジェクトを作成する必要があります。

jQuery オブジェクトの生成は次のように行います。

$(引数)
JQuery(引数)

JQuery オブジェクトを生成する。

引数 (注:次の(1)~(4)を参照)

戻り値:JQuery オブジェクト

上記の2つは同じ意味です。どちらを記述しても同じですが、普通は最初の形式を記述することが多いです。

生成される JQuery オブジェクトは、引数の指定によって1つであったり複数であったりします。そこで、いくつ生成されたかを調べたい場合は、length というプロパティを参照します。

プロパティ
lengthR/OjQuery オブジェクトのエレメント数
記述例
<div></div><div></div><div></div>    // DIV 要素は3つ
<span id="d1"></span><br>
<script>
var n = $("div").length;            // DIV 要素の数を取得する
d1.textContent = n;
</script>
実行例

JQuery オブジェクトの生成は、引数の違いによって次の5種類があります。

(1)セレクタ

「セレクタ」とは、jQuery から操作したい「HTML 要素の場所」です。「13.2 セレクタ」を参照してください。

$(セレクタ[, コンテキスト])

JQuery オブジェクトを生成する。

引数 セレクタ:スタイルシートを適用する要素や jQuery から操作したい要素

引数 コンテキスト:セレクタの検索範囲である、DOM 要素、document、jQuery オブジェクト

戻り値:JQuery オブジェクト

記述例
<span id="d01">xxxxx</span><br>
<span class="c01">xxxxx</span><br>
<span><u>xxxxx</u><b><u>xxxxx</u></b></span><u>.....</u>

<script>
$("#d01").text("Hello");           // id を指定
$(".c01").text("Hello");           // class を指定
$("u", "span").text("Hello");      // span の中の u を指定(直下でなくても対象になる)
</script>

記述例の背景色が黄色くなっている部分がセレクタで指定された jQuery オブジェクト(操作の対象となる要素)です。

上の例は jQuery を使用しなければ次のように書くこともできます。

なお、[].slice.call は Array.prototype.slice.call と書くこともでき、getElementsByClassName などの戻り値を Array オブジェクトに変換します。

document.getElementById("d01").textContent = "Hello";      // id を指定
var c = [].slice.call(document.getElementsByClassName("c01"));    // class を指定
c.forEach(function(e){e.textContent = "Hello";});
var s = [].slice.call(document.querySelectorAll("span u"));       // tag を指定
s.forEach(function(e){e.textContent = "Hello";});
実行例(jQuery 使用)
実行例(jQuery 未使用)

(2)DOM 要素

document.getElementById などで得られた DOM 要素を指定します。DOM 要素については「1.6 ドキュメントオブジェクトモデル」を参照してください。

$(DOM要素)
$([DOM要素1, DOM要素2, ... ,DOM要素N])  [ ] は省略ではなく、配列の意味です

JQuery オブジェクトを生成する。

引数 DOM要素:HTML で記述された各要素を取り扱うための標準インタフェース

    DOM要素が配列のときは、該当する要素全て

戻り値:JQuery オブジェクト

記述例
<span id="d01">xxxxx</span> <span id="d02">...</span><br>
<span id="d11">xxxxx</span> <span id="d12">...</span> <span id="d13">xxxxx</span><br>
<u>xxxxx</u> <u>xxxxx</u> <u>xxxxx</u><br>

<script>
$(d01).text("AAAAA");                                 // d01 を指定
$([d11, d13]).text("BBBBB");                          // d11, d13 を指定
$(document.getElementsByTagName("u")).text("CCCCC");  // u 要素を指定
</script>

多くのブラウザでは id で指定された名前を付けられた変数が暗黙のうちに定義されているので、id 名をそのまま変数として使用することができます。

記述例の背景色が黄色くなっている部分が DOM 要素で指定された jQuery オブジェクト(操作の対象となる要素)です。

上の例は jQuery を使用しなければ次のように書くこともできます。

なお、[].slice.call は Array.prototype.slice.call と書くこともでき、querySelectorAll などの戻り値を Array オブジェクトに変換します。

d01.textContent = "AAAAA";                            // d01 を指定
var id = [].slice.call(document.querySelectorAll("#d11, #d13"));     // d11, d13 を指定
id.forEach(function(e){e.textContent = "BBBBB";});
var u = [].slice.call(document.getElementsByTagName("u"));           // u 要素を指定
u.forEach(function(e){e.textContent = "CCCCC";});
実行例(jQuery 使用)
実行例(jQuery 未使用)

(3)HTML

HTMLの文字列から、DOM 要素を作成します。

$(HTML[, props])

JQuery オブジェクトを生成する。

引数 HTML:HTML要素を定義する文字列

引数 props:追加したい属性、イベントなど(JSON 形式のオブジェクト)

名前意味
classスタイルシートのクラス名'sample'
htmlHTML 要素、文字列'<u>AAA</u>'、'BBB'
cssスタイルシートcolor:'red'
イベント名イベントハンドラーfunction() { ... }

戻り値:JQuery オブジェクト

記述例
<head>
<style>
.x { color:green; }
</style>
</head>
<body>
<script>
$("<span>", {html:'AAAAA',css:{color:'red'}}).appendTo("body"); // 文字列のみのコンテンツとスタイルシート
$("<span>", {html:'<u>BBBBB</u>',class:'x'}).appendTo("body");  // タグを含んだコンテンツとスタイルシートのクラス
$("<span style='color:blue;'>CCCCC</span>").appendTo("body");   // スタイルシートやコンテンツを記述した HTML
</script>
</body>

なお、~.appendTo("body") は、jQuery オブジェクトを body 要素に追加します。したがって、上の例の jQuery の記述部分は次のように書かれていたかのように表示されます。

<span style="color:red;">AAAAA</span>
<span class="x"><u>BBBBB</u></span>
<span style="color:blue;">CCCCC</span>

また、上の例は jQuery を使用しなければ次のように書くこともできます。

var span1 = document.createElement("span");     // 文字列のみのコンテンツとスタイルシートを指定
span1.textContent = "AAAAA";
span1.style.color = "red";
document.body.appendChild(span1);
var span2 = document.createElement("span");     // タグを含んだコンテンツとスタイルシートのクラスを指定
span2.innerHTML = "<u>BBBBB</u>";
span2.className = "x";
document.body.appendChild(span2);
var span3 = document.createElement("span");     // (スタイルシートやコンテンツを記述した HTML を指定)
span3.textContent = "CCCCC";
span3.style.color = "blue";
document.body.appendChild(span3);
実行例(jQuery 使用)
実行例(jQuery 未使用)

また、イベントも記述できます。

記述例
<span id="d01"></span><br>
<script>
$("span", {html:'今の時刻',mouseover:function(){d01.textContent=(new Date()).toLocaleString();},
                          mouseout:function(){d01.textContent=""}}).appendTo("body");     // イベントを指定
</script>

なお、上の例の jQuery の記述部分は次のように書かれていたかのように表示されます。

<span onmouseover="d01.textContent=(new Date()).toLocaleString();" onmouseout="d01.textContent='';">今の時刻</span>

また、上の例は jQuery を使用しなければ次のように書くこともできます。

var span = document.createElement("span");     // 
span.textContent = "今の時刻";
document.body.appendChild(span);
var mouseover = {
  handleEvent:
    function(event) {
      d01.textContent=(new Date()).toLocaleString();
    }
};
var mouseout = {
  handleEvent:
    function(event) {
      d01.textContent="";
    }
};
span.addEventListener('mouseover', mouseover, false);
span.addEventListener('mouseout', mouseout, false);

「今の時刻」にマウスを重ねると、その上に現在の時刻が表示されます。そして、マウスを外すと時刻が消えます。

実行例(jQuery 使用)
実行例(jQuery 未使用)

(4)jQuery オブジェクト

$(jQuery)

指定された JQuery オブジェクトのコピーを生成する。

引数 JQuery オブジェクト

戻り値:JQuery オブジェクト

あくまでコピーを生成して別変数に代入するので、元の JQuery オブジェクトとは別のものです。ただ、対象としてる DOM 要素が同じというだけです。

記述例
<span id="d01"></span><br>
<script>
var j1 = $("#d01");     // JQuery オブジェクトを生成
var j2 = $(j1);         // j1 のコピーを生成
j1.text("Hello");       // 内容を Hello に変更
j2.css("color", "red"); // 文字色を赤に変更
</script>

また、上の例は jQuery を使用しなければ次のように書くこともできます。

ただし、j1 内の JQuery オブジェクトを代入しているだけなので、j2 内の JQuery オブジェクトは j1 と同じものです。

var j1 = d01;             // DOM オブジェクトを別変数に代入
var j2 = j1;              // j1 のコピーを生成
j1.textContent = "Hello"; // 内容を Hello に変更
j2.style.color = "red";   // 文字色を赤に変更
実行例
実行例

(5)this

$(this)

JQuery オブジェクトを生成する。

引数 this:イベントが発生した DOM 要素

戻り値:JQuery オブジェクト

記述例
<span id="d01">今の時刻</span><br>
<script>
$("#d01").hover(show, hide);
function show() {
  $(this).text((new Date()).toLocaleString());
}
function hide() {
  $(this).text("今の時刻");
}
</script>

また、上の例は jQuery を使用しなければ次のように書くこともできます。

d01.onmouseover = show;
d01.onmouseout = hide;
function show() {
  this.textContent = (new Date()).toLocaleString();
}
function hide() {
  this.textContent = "今の時刻";
}

this は、イベントが発生した DOM 要素で、操作の対象となる DOM 要素になります。イベントで設定した function 内で利用します。

記述例の背景色が黄色くなっている部分が $(this) で指定された jQuery オブジェクト(操作の対象となる要素)です。


「今の時刻」にマウスを重ねると、「今の時刻」の代わりに現在の時刻が表示されます。そして、マウスを外すと元の「今の時刻」が表示されます。

実行例
実行例

this については、「7.5 this」 を参照してください。


13.1.4  jQuery の基本形

jQuery の基本的な形は次の通りです。

$("セレクタ").メソッド(パラメーター)

セレクタは、jQuery の作用対象を指定するのに使用します。セレクタについては 「13.2 セレクタ」 を参照してください。


$(DOM要素).メソッド(パラメーター)

DOM は Document Object Model の略で、HTML で記述された各要素を取り扱うための標準インタフェースです。DOM については 「1.6 ドキュメントオブジェクトモデル」 を参照してください。


$("HTML").メソッド(パラメーター)

HTML はタグなどをそのまま記述します。


$(jQuery).メソッド(パラメーター)

jQuery オブジェクトをそのまま、あるいは jQuery オブジェクトを持つ変数を記述します。


$(this).メソッド(パラメーター)

this を記述します。this はイベントが発生した DOM 要素を指します。this については、「7.5 this」 を参照してください。


記述例
<span class="xx"></span><br>
<span id="d02"></span><br>
<div id="d03"></div>
<span id="d04"></span><br>

<script>
$(".xx").text("Hello");                               // スタイルシートのクラスが xx の要素の内容を Hello にする
$(document.getElementById("d02")).text("Hello");      // id が d02 の要素の内容を Hello にする
$("<span style='color:red;'>Hello</span>").appendTo(document.getElementById("d03")); // id が d03 の要素に HTML を追加する
$($("#d04").text("Hello")).css("color", "green");     // id が d04 の内容を Hello にし、さらに文字色を緑にする
$(document).ready(function() {
  $(this).children().css("background-color", "cyan");
});
</script>

上の例は次のように書かれていたかのように表示されます。

<body onload="this.document.body.style.backgroundColor = 'cyan'">
  <span class="xx">Hello</span><br>
  <span id="d02">Hello</span><br>
  <div id="d03"><span style='color:red;'>Hello</span></div>
  <span id="d04" style='color:green;'>Hello</span><br>
</body>

説明のための文字列も別途表示しています。。

実行例

なお、jQuery オブジェクトの各メソッドは、戻り値として、自身の jQuery オブジェクトを返します。そのため、メソッドの戻り値に対してさらにメソッドを記述するということができます。

記述例
$("#x").text("Hello").css("color", "green");  // 内容を Hello にし、さらに文字色を緑にする

13.1.5  実行のタイミング

head 領域に書かれた javaScriptは、body 領域よりも先に読み込まれます。body 領域の中に書かれた javaScript でも、HTML 要素の前に書かれていれば、同様にその HTML 要素より先に読み込まれます。jQuery では html の様々な要素を操作できますが、「読み込まれていないもの」を操作することはできません。

記述例
<script>
$("#d01").text("Hello");      // span 要素が読み込まれる前に実行される
</script>

<span id="d01">xxxxx</span><br>
<span id="d02">xxxxx</span><br>

<script>
$("#d02").text("Hello");      // span 要素が読み込まれた後に実行される
</script>

読み込まれる前の要素は操作できません。

実行例

そのため html の「ページ構成」を読み込んでから処理を開始するようにするためには、以下のように記述する必要があります。

これならば、すべてのDOM要素を確実に安全に操作できるようになった時点でコードが実行されます。

$(
  function() {
    // ページ構成が読み込まれたら この () 内の処理が実行されます。
  }
);

ただし、この方法では画像の完全な読み込みは待ちません。したがって、大きな画像の場合はすべてが読み込まれる前に実行されてしまうかも知れません。そのため、画像のサイズをもとに何か計算するなど、画像の読み込み後に実行したいときなどは、loadイベントを使用した方が良いでしょう。

$(window).on("load", 
  function() {
    // ページ構成が読み込まれたら この () 内の処理が実行されます。
  }
);
記述例
<script>
var n = 1;
$(
  function() {
    $("#d01").text(n++); // すべてのDOM要素を確実に安全に操作できるようになった時点でコードが実行される(2番目)
  }
);
$(window).on("load",
  function() {
    $("#d02").text(n++); // 画像を含めすべてが読み込まれた時点でコードが実行される(3番目)
  }
);
</script>

<span id="d01"></span><br>
<span id="d02"></span><br>
<span id="d03"></span><br>
<img id="img" src="figures/large.png" style="display:none;">  <!-- とても大きな画像を読み込む。ただし、非表示 -->

<script>
$("#d03").text(n++);     // すぐにコードが実行される(1番目)
</script>
実行例

13.2  セレクタ

「セレクタ」とは、jQuery から操作したい「HTML 要素の場所」です。

基本的に jQuery の書き方は、どの HTML 要素で、どんな事をするのか、という記述方法になるため、まず最初に「どの HTML 要素」かということを決める必要があるわけです。

13.2.1  セレクタ

「セレクタ」には、CSS のスタイルと同じものと jQuery 独自のものがあります。

(1)CSS セレクタ

以下のように CSS でのスタイルと同じように指定します。詳しくは、「2.1.1 セレクタ」を参照してください。

なお、セレクタの部分には要素名だけでなく、jQuery のセレクタも指定できます。

基本
セレクタ操作対象
*すべての要素
要素(タグ)名指定されたタグ名の要素
.クラス名指定されたクラス名を持つ要素
#ID名指定された ID 名を持つ要素
jQuery のセレクタjQuery のセレクタで選択された要素
属性フィルタ
フィルタ操作対象
セレクタ[属性]指定された属性を持つ要素
セレクタ[属性=値]指定された値を持つ属性の要素
セレクタ[属性!=値]指定された値を属性を持たない要素
セレクタ[属性^=文字列]属性値が指定された文字列で始まる属性を持つ要素
セレクタ[属性$=文字列]属性値が指定された文字列で終わる属性を持つ要素
セレクタ[属性*=文字列]属性値が指定された文字列を含む属性を持つ要素
セレクタ[属性1][属性2]...[属性N]指定された属性すべてを持つ要素
子要素フィルタ
フィルタ操作対象
セレクタ:first-child最初の子要素
セレクタ:nth-child(N)N 番目の子が指定の要素のとき
セレクタ:nth-last-child(N)後ろから N 番目の子が指定の要素のとき
セレクタ:last-child最後の子要素が指定の要素のとき
セレクタ:only-child子要素が一つだけの場合の子要素
セレクタ:first-of-type子の、指定の要素の最初の要素
セレクタ:nth-of-type(N)子の、指定の要素の N 番目の要素
セレクタ:nth-last-of-type(N)子の、指定の要素の後ろから N 番目の要素
セレクタ:last-of-type子の、指定の要素の最後の要素
セレクタ:only-of-type子の、指定の要素が一つだけの場合の要素

なお、N は 1から始まります。


:(コロン)を含む ID や属性値などは、そのまま指定するとフィルタと判断され正しく識別されません。

ID の場合は、\\ を前に入れることでエスケープできますが、属性値は駄目なようなので指定に工夫が要ります(下の例では、color: で始まり、red; で終わる属性値を指定しています)。

記述例
<table>
  <tr><td id="xx:d01">xxxxx</td></tr>
  <tr><td style="color:red;">xxxxx</td></tr>
  <tr><td><i>...</i><u>xxxxx</u><i>...</i></td></tr>
  <tr><td><u>...</u><i>...</i><u>xxxxx</u></td></tr>
</table>

<script>
$("#xx\\:d01").text("AAAAA");                        // xx:d01 という ID を持つ要素
$("[style^='color:'][style$='red;']").text("BBBBB"); // style='color:red;' という属性を持つ要素
$("u:nth-child(2)").text("CCCCC");                   // 親要素にとっての2番目の子要素が u 要素のとき
$("u:nth-of-type(2)").text("DDDDD");                 // 親要素にとっての2番目の u 要素
</script>

また、上の例は jQuery を使用しなければ次のように書くこともできます。

なお、[].slice.call は Array.prototype.slice.call と書くこともでき、querySelectorAll などの戻り値を Array オブジェクトに変換します。

document.querySelector("xx\\:d01").textContent = "AAAAA";
var e = [].slice.call(document.querySelectorAll("*[style^='color:'][style$='red;']"));
e.forEach(function(e){e.textContent = "BBBBB";});
document.querySelector("u:nth-child(2)").textContent = "CCCCC";
document.querySelector("u:nth-of-type(2)").textContent = "DDDDD";
実行例(jQuery 使用)
実行例(jQuery 未使用)

(2)jQuery の基本セレクタ

○ 基本フィルタ

条件を付けて要素を選択します。

セレクタは省略できます。省略した場合はすべての要素が対象になります。ただし、header は h1 ~ h6 要素が対象です。

また、インデックスは 0から始まります。

フィルタ操作対象
:rootHTML 要素
セレクタ:first最初の要素
セレクタ:last最後の要素
セレクタ:even偶数番の要素
セレクタ:odd奇数番の要素
セレクタ:eq(インデックス)インデックス 番目の要素 (インデックス:0~)
セレクタ:gt(インデックス)インデックス 番目より後の要素 (インデックス:0~)
セレクタ:lt(インデックス)インデックス 番目より前の要素 (インデックス:0~)
セレクタ:not(セレクタ)指定したセレクターを除外した要素
セレクタ:headerh1 ~ h6 要素
セレクタ:animatedjQuery のアニメーション中の要素
セレクタ:lang(言語)指定した言語の要素(言語コード一覧)

記述例
<h4></h4>
<table>
  <tr><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td></tr>
</table>
<span id="anim" style="background-color:cyan;">..........</span><span style="background-color:lightyellow;">..........</span>
<br>
<br>
<span lang="ja"><q>こんにちは</q>は日本語、<q lang="en">Hello</q>は英語。</span>

<script>
$(":root").css("background-color","lightyellow");       // HTML 要素の背景色を lightyellow にする
$("td:even").css("background-color", "lightgrey");      // 偶数番目の TD 要素の背景色を lightgrey にする
$("td:odd").css("background-color", "mintcream");       // 奇数番目の TD 要素の背景色を mintcream にする
$("td:eq(5)").text("= 5");                              // 5番目の TD 要素を "= 5" にする
$("td:gt(6)").text("> 6");                              // 6番目より後ろの TD 要素を "> 6" にする
$("td:lt(2)").text("< 2");                              // 2番目より前の TD 要素を "< 2" にする
$("td:first").text("first");                            // 最初の TD 要素を "first" にする
$("td:last").text("last");                              // 最後の TD 要素を "last" にする
$("h4:header").text("header");                          // H4 要素を "header" にする
$("q:lang(en)").css("background-color","cyan");         // lang=en の Q 要素の背景色を cyan にする
$("q:not(:lang(en))").css("background-color","salmon"); // lang=en ではない Q 要素の背景色を salmon にする

animateIt();     // jQuery でアニメーションを開始する
$("span:animated").text("animated");        // jQuery でアニメーション中の SPAN 要素を "animated" にする

function animateIt() {
  $("#anim").fadeToggle(3000, animateIt);   // jQuery でフェードイン、フェードアウトを繰り返すアニメーション
}
</script>

また、上の例は jQuery を使用しなければ次のように書くこともできます。

アニメーションに関してはちょっと無理やり感がありますが...

なお、[].slice.call は Array.prototype.slice.call と書くこともでき、querySelectorAll などの戻り値を Array オブジェクトに変換します。

document.querySelector(":root").style.backgroundColor = "lightyellow";
var e = [].slice.call(document.querySelectorAll("td:nth-child(odd)"));   // 1から始まるので、最初は奇数
e.forEach(function(e){e.style.backgroundColor = "lightgrey";});
e = [].slice.call(document.querySelectorAll("td:nth-child(even)"));
e.forEach(function(e){e.style.backgroundColor = "mintcream";});
document.querySelector("td:nth-child(6)").textContent = "= 5";     // 1から始まるので、6番目
e = [].slice.call(document.getElementsByTabName("td"));
e.forEach(function(e, i){if (i > 6) e.textContent = "> 6";});
e.forEach(function(e, i){if (i < 2) e.textContent = "< 2";});
document.querySelector("td:first-child").textContent = "first";
document.querySelector("td:last-child").textContent = "last";
e = [].slice.call(document.querySelectorAll("h4:nth-child(n)"));
e.forEach(function(e){e.textContent = "header";});
e = [].slice.call(document.querySelectorAll("q:lang(en)"));
e.forEach(function(e){e.style.backgroundColor = "cyan";});
e = [].slice.call(document.querySelectorAll("q:not(:lang(en))"));
e.forEach(function(e){e.style.backgroundColor = "salmon";});

animateIt();
document.querySelector("span[data-animated]").textContent = "animated";

var opacity = 1;
var direction = -1/12;
function animateIt() {
  document.getElementById("anim").setAttribute("data-animated","");
  window.setInterval(function(){
    fadeToggle("anim")
  }, 3000/12);     
}
function fadeToggle(id) {
  document.getElementById(id).style.opacity = opacity;
  if (opacity <= 0) {
    direction = -direction;
    opacity = direction;
  }
  else if (opacity >= 1) {
    direction = -direction;
    opacity = 1 + direction;
  }
  else {
    opacity += direction;
  }
}

全体の背景色が lightyellow になり、H4 要素に "header" が書かれます。

偶数番目の TD 要素の背景色が lightgrey に、奇数番目の TD 要素の背景色が mintcream になります。

"< 2" は最初の2つの TD 要素に、"> 6" は最後の3つの TD 要素に書かれますが、その後から 最初の TD 要素に "first"、最後の TD 要素に "last" が書かれます。

そして、フェードイン、フェードアウトを繰り返す SPAN 要素に "animated" が書かれます。

実行例(jQuery 使用)
実行例(jQuery 未使用)

○ コンテンツフィルタ

要素の内容を指定し要素を選択します。

フィルタ操作対象
セレクタ:contains(テキスト)指定されたテキストを文字列の一部に持つ(あるいは文字列に一致する)要素
セレクタ:empty空の(要素内に文字列を持たない)要素
セレクタ:has(セレクタ)指定したセレクタが記述された要素を子孫に持つ要素
セレクタ:parentなんらかの文字列や要素を持つ要素


記述例
<table>
  <tr><td></td><td>one</td><td>two</td><td></td><td>four</td><td>five</td><td>six</td><td>seven</td><td></td><td>nine</td></tr>
  <tr><td>...</td><td><span class="x">...</span></td><td>...</td><td>...</td><td>...</td><td></td><td>...</td><td>...</td><td>...</td><span class="x">...</span><td>...</td></tr>
</table>

<script>
$("td:contains('ve')").css("color","red");            // "ve" を含む文字列を持つ TD 要素の文字色を red にする
$("td:empty").css("background-color","lightyellow");  // 空の TD 要素の背景色を lightyellow にする
$("td:has('.x')").text("has"); // スタイルシートのクラス x が指定された要素を子孫に持つTD要素の内容を"has"にする
$("td:parent").css("background-color","lavenderblush"); // 親である(文字列を持つか子のある)TD 要素の背景色を lavenderblush にする
</script>

また、上の例は jQuery を使用しなければ次のように書くこともできます。

なお、[].slice.call は Array.prototype.slice.call と書くこともでき、querySelectorAll などの戻り値を Array オブジェクトに変換します。

var e = [].slice.call(document.querySelectorAll("td:not(:empty)"));
e.forEach(function(e){if (e.textContent.indexOf("ve") >= 0) e.style.color = "red";});
var t = edocument.querySelectorAll("td:empty"));
t.forEach(function(e){e.style.backgroundColor = "lightyellow";});
t = [].slice.call(document.getElementsByTagName("td"));
t.forEach(function(e){
                let x = [].slice.call(e.querySelectorAll(".x"));
                x.forEach(function(e){ e.textContent = "has"; })
              });
t.forEach(function(e){if (e.hasChildNodes()) e.style.backgroundColor = "lavenderblush";});

"ve" を含む("five"、"seven")TD の要素の文字色が red になります。

空の TD 要素の背景色を lightyellow に、空でない TD 要素の背景色が lavenderblush になります。

スタイルシートのクラス x が指定された TD 要素の内容に "has" が書かれます。

実行例(jQuery 使用)
実行例(jQuery 未使用)

○ 可視性フィルタ

要素の表示/非表示を指定し要素を選択します。

フィルタ操作対象
セレクタ:hidden非表示の要素や、hidden 属性の input 要素
セレクタ:visible可視状態にある要素


記述例
<span id="d1">xxx</span><br>
<span id="d2" hidden>xxx</span><br>
<span id="d3"></span><br>

<script>
$("span:visible").text("VISIBLE");    // hidden 属性でない span 要素の内容を VISIBLE にする
$("span:hidden").text("HIDDEN");      // hidden 属性の span 要素の内容を HIDDEN にする

var v = document.getElementById("d2").textContent;
document.getElementById("d3").textContent = v;
</script>

また、上の例は jQuery を使用しなければ次のように書くこともできます。

なお、[].slice.call は Array.prototype.slice.call と書くこともでき、querySelectorAll などの戻り値を Array オブジェクトに変換します。

var e = [].slice.call(document.querySelectorAll("span:not([hidden])"));
e.forEach(function(e){e.textContent = "VISIBLE";});
e = [].slice.call(document.querySelectorAll("span[hidden]"));
e.forEach(function(e){e.textContent = "HIDDEN";});

hidden 属性の span 要素の内容を変更しています。ただ、それでは変更されてもわからないので、そこから取り出して hidden 属性でない span 要素に入れて見えるようにしています。

実行例(jQuery 使用)
実行例(jQuery 未使用)

○ フォームフィルタ

form 要素内で使用される要素を選択します。

フィルタ操作対象
セレクタ:checkedchecked 属性のある type="checkbox" か type="radio の input 要素
セレクタ:disableddisabled 属性のある input 要素
セレクタ:enabledenabled 属性のある input 要素
セレクタ:focusfocus 属性のある input 要素
セレクタ:selectedselected 属性のある input 要素

また、次のような記述もできますが、推奨される記述の方が高速だといわれています。

フィルタ操作対象推奨
:buttontype="button" の input 要素、button 要素button, input[type='button']
:checkboxtype="checkbox" の input 要素input[type='checkbox']
:filetype="file" の input 要素input[type='file']
:imagetype="image" の input 要素input[type='image']
:inputinput 要素input
:passwordtype="password" の input 要素input[type='password']
:radiotype="radio" の input 要素input[type='radio']
:resettype="reset" の input 要素input[type='reset']
:submittype="submit" の input 要素、button 要素input[type='submit']
:texttype="text" の input 要素input[type='text']


記述例
<label><input type="checkbox" name="check">A</label> <label><input type="checkbox" name="check" checked>B</label> <label><input type="checkbox" name="check" disabled>C</label> <label><input type="checkbox" name="check" autofocus>D</label><br>
<select name="select" size="4">
  <option value="1">AAAAA</option>
  <option value="2" selected>BBBBB</option>
  <option value="3">CCCCC</option>
  <option value="4">DDDDD</option>
</select>

<script>
$("input[type='checkbox']:checked").parent().css("border","solid 1px red");        // checked 属性に赤い枠
$("input:not([type='checkbox']:checked)").parent().css("border","solid 1px blue");        // その他は青い枠
$("input[type='checkbox']:disabled").parent().css("background-color","lightgrey"); // disabled 属性の背景色を灰色
$("input[type='checkbox']:enabled").parent().css("background-color","yellow"); // enabled 属性の背景色を黄色
$("option:selected").css("background-color","lightgreen");                 // selected 属性の背景色を薄い緑色
$("input").click(function(){
  $("input").parent().css("border-width","1px");
  $("input:focus").parent().css("border-width","3px");     // フォーカスが当たっている要素の枠を太くする
});
</script>

また、上の例は jQuery を使用しなければ次のように書くこともできます。

なお、[].slice.call は Array.prototype.slice.call と書くこともでき、querySelectorAll などの戻り値を Array オブジェクトに変換します。

var e = [].slice.call(document.querySelectorAll("input[type='checkbox']"));
e.forEach(function(e){e.parentNode.style.border = e.hasAttribute("checked") ? "solid 1px red" : "solid 1px blue";});
e.forEach(function(e){e.parentNode.style.backgroundColor = e.hasAttribute("disabled") ? "lightgrey" : "yellow";});
e = [].slice.call(document.querySelectorAll("option[selected]"));
e.forEach(function(e){e.style.backgroundColor = "lightgreen";});
e = [].slice.call(document.querySelectorAll("input[type='checkbox']"));
e.forEach(function(e){
           e.onclick = function() {
              let c = [].slice.call(document.querySelectorAll("input[type='checkbox']"));
              c.forEach(function(e){e.parentNode.style.borderWidth = "1px";});
              document.querySelector("input[type='checkbox']:focus").parentNode.style.borderWidth = "3px";
           }
         });

赤い枠は初期状態でチェックがついているチェックボックスにだけつきます。チェックするイベントによって枠を付けているわけではないので、後からチェックしても赤い枠はつきません(初期状態でチェックがついていないチェックボックスには青い枠を付けています)。

そして、クリックするたびにフォーカスのある要素の枠を太くしていますが、クリックした要素にフォーカスが当たるので結果的にクリックした要素の枠が太くなります)。

なお、.parent() は、対象要素の親要素を意味します。対象要素が input であれば、その親要素は label になります。

実行例(jQuery 使用)


実行例(jQuery 未使用)



13.2.2  結合子

「セレクタ」と「セレクタ」との関係を指定する結合子には次のようなものがあります。

(1)CSS 結合子

以下のように CSS での結合子と同じように指定します。詳しくは、「2.1.2 結合子」を参照してください。

階層操作対象
セレクタ1 セレクタ2セレクタ1要素の子孫となるセレクタ2要素(セレクタ1要素の内部に記述されたセレクタ2要素)
セレクタ1 > セレクタ2セレクタ1要素の子となるセレクタ2要素(セレクタ1要素内の直下の階層のセレクタ2要素)
セレクタ1 + セレクタ2セレクタ1要素の直後に隣接しているセレクタ2要素
セレクタ1 ~ セレクタ2セレクタ1要素の後ろにある同じ階層のセレクタ2要素
セレクタ1, セレクタ2, ... , セレクタNいずれかのセレクタに一致する要素
記述例
<table>
  <tr><td id="d01"><span>..<u>xxx</u>..</span> <u>xxx</u></span> <u>...</u></td></tr>
  <tr><td id="d02">..<u>xxx</u>... <span>..<u>...</u>...</span> ...</td></tr>
  <tr><td id="d03">.. <u>...</u> <span>...</span> <u>xxx</u> ... <u>...</u></td></tr>
  <tr><td id="d04">.. <u>...</u> <span>...</span> <u>xxx</u> ... <u>xxx</u></td></tr>
  <tr><td id="d05">.. <u>xxx</u> <u>...</u> <span>xxx</span> ... <u>...</u></td></tr>
</table>

<script>
$("#d01 u").text("AAAAA");                 // d01 という ID を持つ要素の子孫である u 要素
$("#d02>u").text("BBBBB");                 // d02 という ID を持つ要素の直下の階層の u 要素
$("#d03 span+u").text("CCCCC");            // d03 という ID を持つ要素内の span 要素のとなりの u 要素
$("#d04 span~u").text("DDDDD");            // d04 という ID を持つ要素内の span 要素の後ろの同じ階層の u 要素
$("#d05 u:first, #d05 span").text("EEEEE"); // d05 という ID を持つ要素内の最初の u 要素か span 要素
</script>

, と空白では、, が優先されます。したがって、5番目の例の2つ目の #d05 は重要です。2つ目の #d05 があれば #d05 の子孫の span 要素を示しますが、#d05 がなければすべての span 要素を示すことになります。

また、上の例は jQuery を使用しなければ次のように書くこともできます。

なお、[].slice.call は Array.prototype.slice.call と書くこともでき、querySelectorAll などの戻り値を Array オブジェクトに変換します。

var e = [].slice.call(document.querySelectorAll("#d01 u"));
e.forEach(function(e){e.textContent = "AAAAA";});
e = [].slice.call(document.querySelectorAll("#d02>u"));
e.forEach(function(e){e.textContent = "BBBBB";});
e = [].slice.call(document.querySelectorAll("#d03 span+u"));
e.forEach(function(e){e.textContent = "CCCCC";}));
e = [].slice.call(document.querySelectorAll("#d04 span~u"));
e.forEach(function(e){e.textContent = "DDDDD";});
e = [].slice.call(document.querySelectorAll("#d05 u:first-child, #d05 span"));
e.forEach(function(e){e.textContent = "EEEEE";});
実行例(jQuery 使用)
実行例(jQuery 未使用)

(2)jQuery 結合子

階層操作対象
[セレクタ1][セレクタ2] ... [セレクタN]すべてのセレクタに一致する要素
[セレクタ1],[セレクタ2], ... ,[セレクタN]どれかのセレクタに一致する要素
記述例
<table>
  <tr><td id="d01">.. <u id="a1">...</u> <u id="b1" title="aaa">xxx</u> <u>...</u> <u id="c1" title="bbb">...</u></td></tr>
  <tr><td id="d02">.. <u id="a2">xxx</u> <u title="aaa">xxx</u> <u>...</u> <u title="bbb">xxx</u></td></tr>
</table>

<script>
$("#d01 [id][title$='a']").text("AAAAA");       // ID=d01の要素内の、idと'a'で終わるtitle属性の両方を持つ要素
$("#d02 [id],#d02 [title$='a']").text("BBBBB"); // ID=d02の要素内の、id属性か'a'で終わるtitle属性を持つ要素
</script>

, と空白では、, が優先されます。したがって、2番目の例の2つ目の #d02 は重要です。2つ目の #d02 があれば #d02 の子孫の title 要素を示しますが、#d02 がなければすべての title 要素を示すことになります。

また、上の例は jQuery を使用しなければ次のように書くこともできます。

なお、[].slice.call は Array.prototype.slice.call と書くこともでき、querySelectorAll などの戻り値を Array オブジェクトに変換します。

var e = [].slice.call(document.querySelectorAll("#d01 [id][title$='a']"));
e.forEach(function(e){e.textContent = "AAAAA";});
e = [].slice.call(document.querySelectorAll("#d02 [id], #d02 [title$='a']"));
e.forEach(function(e){e.textContent = "BBBBB";});
実行例(jQuery 使用)
実行例(jQuery 未使用)

13.3  jQuery API

13.3.1  主要部

jQuery オブエジェクトの生成と実行に関する処理

(1) 関数の実行

メソッド引数機能戻り値
$().ready(関数)関数DOM の読み込みが完了したときに、関数を実行する。jQuery オブジェクト
$(関数)関数.ready の省略形。この関数に引数(alias)を記述すれば、その引数名を $ の代わりに使用できる。jQuery オブジェクト
記述例
<head>
<script>
$(function() {
  $("#d01").text("AAAAA");
});
$(function(X) {                             // $ の代わりに X を使用する
  X("#d02").text("BBBBB");
});
$().ready(function() {                      // 正式な記述形式
  $("#d03").text("CCCCC");
});
</script>
</head>

<body>
  <span id="d01"></span><br>
  <span id="d02"></span><br>
  <span id="d03"></span><br>
</body>
実行例

(2) 関数の遅延実行

メソッド引数機能戻り値
$().holdReady(論理値)true/falseready イベントの実行を保留(true)したり解除(false)する。なし

DOM の読み込みが完了したときに発生する ready イベントの発生を保留させます。

記述例
<head>
 <script>
  $().ready(function() {      // ready イベントが発生(DOM の読み込みが完了)したときに、関数を実行する。
    $("#d01").text("AAAAA");
  });
  $.holdReady(true);           // ready イベントの発生を保留する
 </script>
</head>
<body>
 <span id="d01"></span><br>
 <button>実行</button>
 <script>
  $("button").click(function(){
      $.holdReady(false);      // ready イベント発生の保留を解除する
  });
 </script>
</body>

[実行]ボタンをクリックすることによって ready イベント発生の保留を解除し、イベントを発生させます。

実行例
再実行


(3) $、jQuery 変数の解放

javaScript では「$」を関数または変数名として使用できます。しかし、jQuery も「$」を「jQuery」の別名として使用しているため jQuery を使用していると「$」が使えません。もし、jQuery と「$」を使用する別の javaScript ライブラリを共存させる必要が有る場合は、 $.noConflict() を実行して、「$」を開放します。

メソッド引数機能戻り値
$.noConflict([removeAll])true:jQuery 変数も開放する(規定値:false)予約されている「$」や jQuery 変数を開放する「$」内のオブジェクト
記述例
<div id="d01"></div>
<!-- 以下略 -->

<script>
$("#d01").text("AAAAA");
var j = $.noConflict();                                                  // $ 変数を解放し、j に設定する
try {$("#d02").text("BBBBB"); } catch(x) { d02.textContent = x; }       // $ は使用できなくなる
j("#d03").text("CCCCC");                                                 // 代わりに j は使用できる
jQuery("#d04").text("DDDDD");                                            // jQuery もまだ使用できる
jQuery.noConflict(true);                                                // jQuery も解放する
try {jQuery("#d05").text("EEEEE"); } catch(x) { d05.textContent = x; }  // jQuery も使用できなくなる
</script>

実行の途中で、noConflict() や noConflict(true) を行っています。そのため、その後は「$」や jQuery が使用できなくなっています(例外が発生しています)。

実行例

13.3.2  jQueryオブジェクト操作

jQueryオブジェクトに関する処理

(1)追加

 (1-1)追加

操作の対象となる jQuery オブジェクトのリストに jQuery オブジェクトをさらに追加します。これにより、操作の対象となる要素が増えます。

メソッド引数機能戻り値
add(追加要素)追加要素:セレクタ、DOM 要素、HTML、jQuery オブジェクト
13.1.3 jQuery オブジェクトの生成 参照)
jQuery オブジェクトに指定した要素を追加する。jQuery オブジェクト
add(追加要素, 検索範囲)追加要素:セレクタ
検索範囲:DOM 要素、document、jQuery オブジェクト
検索範囲内にある jQuery オブジェクトに指定した要素を追加する。jQuery オブジェクト

次の例は、最初に対象となっている要素は赤い文字にし、さらに対象要素を追加し文字列を AAA に変更しています。

記述例
<span id="d01">x</span> <span id="d02">x</span><br>
<span id="d11">x</span> <span id="d12"><i>x</i> <u>x</u></span><br>

<script>
$("#d02").css("color", "red").add("#d01").text("AAA");           // AAA を代入する対象:d02 d01
$("#d11").css("color", "red").add("i", "#d12").text("AAA");      // AAA を代入する対象:d11 d12 内の i 要素
</script>

上の例の jQuery の記述部分は jQuery を使用しなければ、次のように書き換えることもできます。

なお、[].slice.call は Array.prototype.slice.call と書くこともでき、querySelectorAll などの戻り値を Array オブジェクトに変換します。

var target = [d02];
target.forEach(function(e){e.style.color = "red";});
target.push(d01);
target.forEach(function(e){e.textContent = "AAA";});           // AAA を代入する対象:d02 d01
target = [d11];
target.forEach(function(e){e.style.color = "red";});
var temp = [].slice.call(document.querySelectorAll("#d12 > i"));
temp.forEach(function(e){target.push(e);});
target.forEach(function(e){e.textContent = "AAA";});           // AAA を代入する対象:d11 d12 内の i 要素

実行例(jQuery 使用)
実行例(jQuery 未使用)

 (1-2)前の要素の追加
メソッド引数機能戻り値
addBack([絞り込み条件])絞り込み条件:セレクタ
(ひとつ前の状態の jQuery オブジェクトを絞り込むフィルタになる)
現在の jQuery オブジェクトに、ひとつ前の状態の要素を追加する。
絞り込み条件があれば、条件に合うものだけを追加する。
jQuery オブジェクト

nextAll() は、元の対象要素と同じ階層の要素(兄弟要素)で元の対象要素より後の要素を新たに対象とします。最初の例では d02 の次の d03 が、二番目の例では d12 の次の d13 と d22 の次の d23 が対象要素となります。

addBack() は、対象が別の要素に移っていたときに、操作対象となっている要素として、その前の対象要素も付け加えます。そのとき、引数があればフィルタリングされ加えられる要素が制限されます。

最初の例では元の対象要素の d02 が、二番目の例は元の対象要素は d12 と d22 ですが、class として x を持っているのが d12 だけなので、d12 だけが追加されます。

記述例
<span id="d01">x</span> <span id="d02">x</span> <span id="d03">x</span><br>
<span><span id="d11">x</span> <span id="d12" class="x">x</span> <span id="d13">x</span></span>  <span><span id="d21">x</span> <span id="d22">x</span> <span id="d23">x</span></span><br>

<script>
$("#d02").css("color", "red").nextAll().addBack().text("AAA");           // AAA を代入する対象:d03 と d02
$("#d12, #d22").css("color", "red").nextAll().addBack(".x").text("AAA"); // AAA を代入する対象:d13 d23 と d12
</script>

上の例の jQuery の記述部分は jQuery を使用しなければ、次のように書き換えることもできます。

なお、[].slice.call は Array.prototype.slice.call と書くこともでき、querySelectorAll などの戻り値を Array オブジェクトに変換します。

target = [d02];
target.forEach(function(e){
  e.style.color = "red";
  let temp = [].slice.call(document.querySelectorAll("#" + e.id + " ~ " + e.tagName));
  temp.forEach(function(e){target.push(e);});
});
target.forEach(function(e){e.textContent = "AAA";});           // AAA を代入する対象:d03 と d02
target = [d12, d22];
var newTarget = [];
target.forEach(function(e){
  e.style.color = "red";
  let temp = [].slice.call(document.querySelectorAll("#" + e.id + " ~ " + e.tagName));
  temp.forEach(function(e){newTarget.push(e);});
  let cList = e.className.replace(/ \s+/g," ").split(" ");
  if (cList.indexOf("x") >= 0) newTarget.push(e);
});
newTarget.forEach(function(e){e.textContent = "AAA";});        // AAA を代入する対象:d13 d23 と d12

実行例(jQuery 使用)
実行例(jQuery 未使用)

 (1-3)前の要素に戻す
メソッド引数機能戻り値
end()なし現在の jQuery オブジェクトのリストをひとつ前の状態に戻す。
jQuery オブジェクトを前の状態に戻すのではなく、操作対象となる jQuery オブジェクトのリストを変更前に戻す。
jQuery オブジェクト

end() は、操作対象となる jQuery オブジェクトのリストをひとつ前の状態に戻します。

最初の例は、add("#d01") する前の $("#d02") に戻します。

二つ目の例は、addBack(".x") する前の nextAll() した状態に戻します。

記述例
<span id="d01">x</span> <span id="d02">x</span><br>
<span><span id="d11">x</span> <span id="d12" class="x">x</span> <span id="d13">x</span></span>  <span><span id="d21">x</span> <span id="d22">x</span> <span id="d23">x</span></span><br>

<script>
$("#d02").css("color", "red").add("#d01").text("AAA").end().text("BBB");       // BBB を代入する対象:d02
$("#d12, #d22").css("color", "red").nextAll().addBack(".x").text("AAA").end().text("BBB"); // BBB を代入する対象:d13 d23
</script>

上の例の jQuery の記述部分は jQuery を使用しなければ、次のように書き換えることもできます。

この例では、end() によってひとつ前の状態に戻すために状態の変化を履歴として保存しています。

なお、[].slice.call は Array.prototype.slice.call と書くこともでき、querySelectorAll などの戻り値を Array オブジェクトに変換します。

var target = [d02];
target.forEach(function(e){e.style.color = "red";});
target.push(d01);
target.forEach(function(e){e.textContent = "AAA";});           // AAA を代入する対象:d02 d01
target.pop();
target.forEach(function(e){e.textContent = "BBB";});           // BBB を代入する対象:d02
target = [[d12, d22]];
target[0].forEach(function(e){e.style.color = "red"; });
var newTarget = [];
target[0].forEach(function(e){ newTarget = newTarget.concat([].slice.call(
                         document.querySelectorAll("#" + e.id + " ~ " + e.tagName))); }); // nextAll
target[1] = newTarget;
target[2] = [];
target[0].forEach(function(e){
        let cList = e.className.replace(/ \s+/g," ").split(" ");
        if (cList.indexOf("x") >= 0) target[2].push(e); });         // addBack
target[2].forEach(function(e){e.textContent = "AAA"; });
target[1].forEach(function(e){e.textContent = "BBB"; });

実行例(jQuery 使用)
実行例(jQuery 未使用)

(2) 取得

(2-1)部分取得
メソッド引数機能戻り値
first()なし要素の集合から、最初の要素を返す。jQuery オブジェクト
last()なし要素の集合から、最後の要素を返す。jQuery オブジェクト
eq(取得位置)取得位置:数値(0~)
(マイナス値だと終端からの位置)(注1)
要素の集合から、取得位置の要素を返す。jQuery オブジェクト
slice(開始位置[,終了位置])開始位置:数値(0~)
終了位置:数値(0~)(規定値:終端)
(マイナス値だと終端からの位置)(注1)(注2)
要素の集合から、開始位置から終了位置の前までの要素を返す。jQuery オブジェクト
注1)マイナス値で指定した場合、終端の位置は -1
注2)マイナス値で指定しても、開始位置 < 終了位置 でなければならない
記述例
<span id="d01"><span>1</span> <span>2</span> <span>3</span> <span>4</span> <span>5</span><br>
<!-- 以下略 -->

<script>
$("#d01 span").first().css("color", "red");         // 最初が 赤
$("#d02 span").last().css("color", "red");          // 最後が 赤
$("#d03 span").eq(1).css("color", "red");           // 二番目が 赤
$("#d03 span").eq(-1).css("color", "green");        // 最後が 緑
$("#d04 span").slice(0,2).css("color", "red");      // 最初と二番目が 赤
$("#d04 span").slice(-2,-1).css("color", "green");  // 最後から二番目が 緑
</script>

上の例の jQuery の記述部分は jQuery を使用しなければ、次のように書き換えることもできます。

なお、[].slice.call は Array.prototype.slice.call と書くこともでき、querySelectorAll などの戻り値を Array オブジェクトに変換します。

var target = [].slice.call(document.querySelectorAll("#d01 span"));
target[0].style.color = "red";
target = [].slice.call(document.querySelectorAll("#d02 span"));
target[target.length-1].style.color = "red";
target = [].slice.call(document.querySelectorAll("#d03 span"));
target[1].style.color = "red";
target[target.length-1].style.color = "green";
target = [].slice.call(document.querySelectorAll("#d04 span"));
var length = target.length;
for (let i = 0 ; i < 2 ; i++)
  target[i].style.color = "red";
for (let i = length - 2 ; i < length - 1 ; i++)
  target[i].style.color = "green";

実行例(jQuery 使用)
実行例(jQuery 未使用)

(2-2)フィルタリング
メソッド引数機能戻り値
filter(絞り込み条件)絞り込み条件:セレクタ、DOM 要素、jQuery オブジェクト(注1)要素の集合をさらに絞り込んだ要素を返す。jQuery オブジェクト
filter(関数)選択する(true)か、しないか(false)を返す関数
関数の形式
function(index)
 index:   要素番号(0~)
戻り値:  true:選択する、false:選択しない
要素の集合から、true が返った要素だけに絞り込んだ要素を返す。jQuery オブジェクト
has(絞り込み条件)絞り込み条件:セレクタ、DOM 要素(注1)要素の集合の内、絞り込み条件に合う子孫に持つ要素を返す。jQuery オブジェクト
not(除外条件)除外条件セレクタ、DOM 要素、jQuery オブジェクト(注1)要素の集合から除外条件に合う要素を除外した要素を返す。jQuery オブジェクト
not(関数)残さない(true)か、残すか(false)を返す関数
関数の形式
function(index)
 index:   要素番号(0~)
戻り値:  true:残さない、false:残す
要素の集合から、false が返った要素だけに絞り込んだ要素を返す。jQuery オブジェクト
注1)13.1.3 jQuery オブジェクトの生成 参照
記述例
<span id="d01"><span>1</span> <span>2</span> <span>3</span> <span>4</span> <span>5</span><br>
<span id="d02"><span>1</span> <span>2</span> <span>3</span> <span>4</span> <span>5</span><br>
<span id="d03"><span>1</span> <i>2</i> <span><i>3</i></span> <span>4</span> <span><u><i>5</i></u></span><br>
<span id="d04"><span>1</span> <span>2</span> <span>3</span> <span>4</span> <span>5</span><br>
<span id="d05"><span>1</span> <span>2</span> <span>3</span> <span>4</span> <span>5</span><br>

<script>
$("#d01 span").filter($(":nth-child(2)").css("color", "red");                    // 二番目が 赤
$("#d02 span").filter(function(i){ return i % 2 == 0; }).css("color", "red");  // 偶数番目が 赤
$("#d03 span").has("i").css("color", "red");                                     // 三番目と五番目が 赤
$("#d04 span").not(":nth-child(2)").css("color", "red");                         // 二番目以外が 赤
$("#d04 span").not(function(i){ return i % 2 == 0; }).css("color", "red");     // 奇数番目が 赤
</script>

上の例の jQuery の記述部分は jQuery を使用しなければ、次のように書き換えることもできます。

なお、[].slice.call は Array.prototype.slice.call と書くこともでき、querySelectorAll などの戻り値を Array オブジェクトに変換します。

document.querySelector($("#d01 span:nth-child(2)").style.color = "red";
var target = [].slice.call(document.querySelectorAll($("#d02 span"));
target.forEach(function(e, i){if (i % 2 == 0) e.style.color = "red";});
target = [].slice.call(document.querySelectorAll($("#d03 span"));
target.forEach(function(e){if (hasChild(e, "i")) e.style.color = "red";});
target = [].slice.call(document.querySelectorAll($("#d04 span:not(:nth-child(2))"));
target.forEach(function(e){e.style.color = "red";});
target = [].slice.call(document.querySelectorAll($("#d05 span"));
target.forEach(function(e, i){if (i % 2 != 0) e.style.color = "red";});

function hasChild(e, tag) {
  tag = tag.toUpperCase();
  let children = [].slice.call(e.childNodes);
  for (let i = 0 ; i < children.length ; i++) {
    if (children[i].tagName == tag)
      return true;
    if (hasChild(children[i], tag) == true)
      return true;
  }
  return false;
}

実行例(jQuery 使用)
実行例(jQuery 未使用)

(2-3)兄弟要素

対象となっている要素の兄弟(同じ階層の)要素を取得します。対象となる要素と同じ種類の(タグ名が同じとか同じ属性を持つ)要素である必要はありません。あくまで、対象となっている要素の次あるいは前の要素からが検査対象となります。

メソッド引数機能戻り値
next([選択条件])選択条件:セレクタ直後の要素を返す。ただし、選択条件が指定されていれば、それに一致した場合のみ、その要素を返す。jQuery オブジェクト
nextAll([選択条件])選択条件:セレクタ次以降のすべての要素を返す。ただし、選択条件が指定されている場合はそれに一致する要素のみを返す。jQuery オブジェクト
nextUntil([終了条件]
          [,絞り込み条件])
終了条件:セレクタ、DOM要素
絞り込み条件:セレクタ
次以降で終了条件に一致するまでの要素をすべて返す(一致した要素は含まれない)。ただし、絞り込み条件が指定されている場合はそれに一致する要素のみを返す。jQuery オブジェクト
prev([選択条件])選択条件:セレクタ直前の要素を返す。ただし、選択条件が指定されていれば、それに一致した場合のみ、その要素を返す。jQuery オブジェクト
prevAll([選択条件])選択条件:セレクタ直前の要素から最初の項目までのすべての要素を返す。ただし、選択条件が指定されている場合はそれに一致する要素のみを返す。jQuery オブジェクト
prevUntil([終了条件]
          [,絞り込み条件])
終了条件:セレクタ、DOM要素
絞り込み条件:セレクタ
直前の要素から前に向かって検査し、終了条件に一致するまでの要素をすべて返す(一致した要素は含まれない)。ただし、絞り込み条件が指定されている場合はそれに一致する要素のみを返す。jQuery オブジェクト
siblings([選択条件])選択条件:セレクタ兄弟要素を返す。ただし、選択条件が指定されている場合はそれに一致する要素のみを返す。jQuery オブジェクト
注)セレクタ、DOM要素 に関しては、13.1.3 jQuery オブジェクトの生成 参照

○ next、nextAll、nextUntil

next、nextAll、nextUntil は対象となっている要素の次から最後に向かって検査します。次の例では2番目の要素が対象となっているので、検査対象は3番目からです。

また、検査対象の最後は、nextAll では兄弟要素の最後、nextUntil では兄弟要素中で指定したフィルタに合致した要素の前までになります。

記述例
<span id="d01"><span>1</span> <b>2</b> <span>3</span> <span class="d">4</span> <span>5</span><br>
<span id="d02"><span>1</span> <b>2</b> <span class="c">3</span> <span class="d">4</span> <span>5</span><br>
<span id="d03"><span>1</span> <b>2</b> <span class="c">3</span> <span class="d x">4</span> <span id="x">5</span><br>

<script>
$("#d01 :nth-child(2)").next().css("color", "red");                     // 三番目が 赤
$("#d01 :nth-child(2)").next("[id]").css("font-weight", "bold");        // 三番目に id がないので変更なし
$("#d01 :nth-child(2)").next("[class]").css("font-style", "italic");    // 三番目に class があるので斜体文字
$("#d02 :nth-child(2)").nextAll().css("color", "red");                  // 三番目以降が 赤
$("#d02 :nth-child(2)").nextAll("[class]").css("font-style", "italic"); // 三番目、四番目に class があるので斜体文字
$("#d03 :nth-child(2)").nextUntil("[id]").css("color", "red");                  // 三番目、四番目が 赤
$("#d03 :nth-child(2)").nextUntil("[id]", ".d").css("font-style", "italic");    // 四番目が斜体文字
</script>

上の例の jQuery の記述部分は jQuery を使用しなければ、次のように書き換えることもできます。

var target = document.querySelector("#d01 :nth-child(2)");
var nextNode = getNext(target);
if (nextNode != undefined) {
  nextNode.style.color = "red";
  if (nextNode.id != "")
    nextNode.style.fontWeight = "bold";
  if (nextNode.className != "")
    nextNode.style.fontStyle = "italic";
}
target = document.querySelector("#d02 :nth-child(2)");
nextNode = getNext(target);
while(nextNode != undefined) {
  if (nextNode.id != "")
    break;                        // id がある要素まで繰り返し
  nextNode.style.color = "red";
  if (nextNode.className != "")                        // class あり
    nextNode.style.fontStyle = "italic";
  nextNode = getNext(nextNode);
}
target = document.querySelector("#d03 :nth-child(2)");
nextNode = getNext(target);
while(nextNode != undefined) {
  if (nextNode.id != "")
    break;                        // id がある要素まで繰り返し
  nextNode.style.color = "red";
  let cList = nextNode.className.replace(/ \s+/g," ").split(" ");
  if (cList.indexOf("d") >= 0)                        // class="d" あり
    nextNode.style.fontStyle = "italic";
  nextNode = getNext(nextNode);
}

function getNext(me) {
  let parent = me.parentNode;       // 親ノード
  let siblings = parent.childNodes;  // 兄弟ノード
  let i = 0;
  for ( ; i < siblings.length ; i++) {
    if (siblings[i].isEqualNode(me))
      break;                        // 自分自身
  }
  while (++i < siblings.length) {
    if (siblings[i].tagName != undefined)
      return  siblings[i];           // 次のノード
  }
  return undefined;     // 次がなかった
}

実行例(jQuery 使用)
実行例(jQuery 未使用)


○ prev、prevAll、prevUntil

prev、prevAll、prevUntil は対象となっている要素の前から最初に向かって検査します。次の例では4番目の要素が対象となっているので、検査対象は3番目からです。

また、検査対象の最後は、prevAll では兄弟要素の最初、prevUntil では兄弟要素中で指定したフィルタに合致した要素の次(検査開始要素に近い側)までになります。

記述例
<span id="d01"><span>1</span> <span id="c12">2</span> <span id="c13">3</span> <b>4</b> <span>5</span><br>
<span id="d02"><span>1</span> <span class="b">2</span> <span class="c">3</span> <b>4</b> <span>5</span><br>
<span id="d03"><span id="c31">1</span> <span class="b x">2</span> <span class="c">3</span> <b>4</b> <span>5</span><br>

<script>
$("#d01 :nth-child(4)").prev().css("color", "red");                     // 三番目が 赤
$("#d01 :nth-child(4)").prev(c12).css("font-weight", "bold");           // 三番目に id がないので変更なし
$("#d01 :nth-child(4)").prev(c13).css("font-style", "italic");          // 三番目に class があるので斜体文字
$("#d02 :nth-child(4)").prevAll().css("color", "red");                  // 三番目以前が 赤
$("#d02 :nth-child(4)").prevAll("[class]").css("font-style", "italic"); // 三番目、二番目に class があるので斜体文字
$("#d03 :nth-child(4)").prevUntil(c31).css("color", "red");                  // 三番目、二番目が 赤
$("#d03 :nth-child(4)").prevUntil(c31, ".b").css("font-style", "italic");    // 二番目が斜体文字
</script>

上の例の jQuery の記述部分は jQuery を使用しなければ、次のように書き換えることもできます。

var target = document.querySelector("#d01 :nth-child(4)");
var prevNode = getPrev(target);
if (prevNode != undefined) {
  prevNode.style.color = "red";
  if (prevNode.isEqualNode(c12))
    prevNode.style.fontWeight = "bold";
  if (prevNode.isEqualNode(c13))
    prevNode.style.fontStyle = "italic";
}
target = document.querySelector("#d02 :nth-child(4)");
prevNode = getPrev(target);
while(prevNode != undefined) {
  if (prevNode.isEqualNode(c31))
    break;                        // id がある要素まで繰り返し
  prevNode.style.color = "red";
  if (prevNode.className != "")                        // class あり
    prevNode.style.fontStyle = "italic";
  prevNode = getPrev(prevNode);
}
target = document.querySelector("#d03 :nth-child(4)");
prevNode = getPrev(target);
while(prevNode != undefined) {
  if (prevNode.isEqualNode(c31))
    break;                        // id がある要素まで繰り返し
  prevNode.style.color = "red";
  let cList = prevNode.className.replace(/ \s+/g," ").split(" ");
  if (cList.indexOf("b") >= 0)                        // class="b" あり
    prevNode.style.fontStyle = "italic";
  prevNode = getPrev(prevNode);
}

function getPrev(me) {
  let parent = me.parentNode;       // 親ノード
  let siblings = parent.childNodes;  // 兄弟ノード
  let i = siblings.length-1;
  for ( ; i >= 0 ; i--) {
    if (siblings[i].isEqualNode(me))
      break;                        // 自分自身
  }
  while (--i >= 0) {
    if (siblings[i].tagName != undefined)
      return  siblings[i];           // 次のノード
  }
  return undefined;     // 次がなかった
}

実行例(jQuery 使用)
実行例(jQuery 未使用)

○ siblings

siblings は対象となっている要素と同じ階層の要素を検査します。次の例では4番目の要素が対象となっているので、検査対象は4番目以外のすべてです。

記述例
<span id="d01"><span>1</span> <span>2</span> <span>3</span> <b>4</b> <span>5</span><br>
<span id="d02"><span>1</span> <span class="b">2</span> <span class="c">3</span> <b>4</b> <span>5</span><br>

<script>
$("#d01 :nth-child(4)").siblings().css("color", "red");                         // 四番目が 赤
$("#d01 :nth-child(4)").siblings(":not([class])").css("color", "red");          // 一番目、五番目が 赤
</script>

上の例の jQuery の記述部分は jQuery を使用しなければ、次のように書き換えることもできます。

var target = document.querySelector("#d01 :nth-child(4)");
var nextNode = getFirst(target);
while(nextNode != undefined) {
  if (!nextNode.isEqualNode(target))
    nextNode.style.color = "red";
  nextNode = getNext(nextNode);
}
target = document.querySelector("#d02 :nth-child(4)");
nextNode = getFirst(target);
while(nextNode != undefined) {
  if (!nextNode.isEqualNode(target))
    if (nextNode.className == "")       // class なし
    nextNode.style.color = "red";
  nextNode = getNext(nextNode);
}

function getFirst(me) {
  let parent = me.parentNode;       // 親ノード
  return parent.childNodes[0];      // 最初の兄弟ノード
}

function getNext(me) {
  let parent = me.parentNode;       // 親ノード
  let siblings = parent.childNodes;  // 兄弟ノード
  let i = 0;
  for ( ; i < siblings.length ; i++) {
    if (siblings[i].isEqualNode(me))
      break;                        // 自分自身
  }
  while (++i < siblings.length) {
    if (siblings[i].tagName != undefined)
      return  siblings[i];           // 次のノード
  }
  return undefined;     // 次がなかった
}

実行例(jQuery 使用)
実行例(jQuery 未使用)

(2-4)子孫要素

対象となっている要素の子孫(対象となっている要素が内部に含んでいる)要素を取得します。対象となる要素と同じ種類の(タグ名が同じとか同じ属性を持つ)要素である必要はありません。

メソッド引数機能戻り値
children([選択条件])選択条件:セレクタ(注)テキストや HTMLコ メント以外の直下の子要素(1階層分だけ)を返す。ただし、選択条件が指定されている場合はそれに一致する要素のみを返す。jQuery オブジェクト
contents()なしテキストや HTML コメントを含むすべての子要素(1階層分だけ)を返す。jQuery オブジェクト
find(選択条件)選択条件:セレクタ、DOM 要素、jQuery オブジェクト(注)指定された要素のすべての子孫要素(すべての階層)を返す。ただし、選択条件が指定されている場合はそれに一致する要素のみを返す。jQuery オブジェクト
注)セレクタ、DOM要素などに関しては、13.1.3 jQuery オブジェクトの生成 参照

chidren と contents との違いは、テキストや HTML コメントを含まないか含むかです。一番目の例は chidren なのでテキスト部分(x という文字列の部分)は赤くなりません。しかし、二番目の例は contents なので赤くなります。

そして、chidren と find との違いは、取得する範囲が直下の1階層だけか、すべての階層かです。D1 の部分は、2階層下なので chidren では赤くなりません(四番目の例)が、find では赤くなります(三番目の例)。

また、chidren と find は、取得された子孫要素をさらに絞り込むことができます。四番目の例は id が記述されていないものだけに絞り込んでいますので、id のある B と C は赤くなりません。chidren に引数のない一番目の例では赤くなっています。

なお、wrap は対象の要素を指定したタグで挟みます。例えば x という文字列はタグで挟まれていないので、スタイルシートで色を指定できません。そこで、赤い文字にするスタイルシートを指定した span 要素で挟むようにしています。

記述例
<div id="d01"><span>A</span> x <span id="b">B</span> <span id="c">C</span> <span><span style="color:blue;">D1</span> D2</span></div>
<!-- 以下略 -->

<script>
$("#d01").children().wrap("<span style='color:red'></span>");  // A B C D2 が 赤
$("#d02").contents().wrap("<span style='color:red'></span>");  // A x B C D2 が 赤
$("#d03").find(":not([id])").css("color", "red");              // A D1 D2 が 赤
$("#d04").children(":not([id])").css("color", "red");          // A D2 が 赤
</script>

上の例の jQuery の記述部分は jQuery を使用しなければ、次のように書き換えることもできます。

var descendant = [];
getDescendant(d01, 1, descendant);
descendant.forEach(function(e){ d01.replaceChild(wrap("style", "color:red", e), e); });
descendant = [];
getDescendant(d02, 1, descendant, true);
descendant.forEach(function(e){ d02.replaceChild(wrap("style", "color:red", e), e); });
descendant = [];
getDescendant(d03, 10, descendant);
descendant.forEach(function(e){ if (e.id == "") e.style.color = "red"; });
descendant = [];
getDescendant(d04, 1, descendant);
descendant.forEach(function(e){ if (e.id == "") e.style.color = "red"; });


function getDescendant(parent, hierarchy, descendant, all) {
  let n = descendant.length;
  let childNodes = parent.childNodes;
  let c = childNodes.length;
  for (let i = 0 ; i < c ; i++) {
    if (childNodes[i].tagName != undefined || all)   // テキストも含める
      descendant[n++] = childNodes[i];
  }
  if (--hierarchy > 0) {
    for (let i = 0 ; i < c ; i++) {
      getDescendant(childNodes[i], hierarchy, descendant);
    }
  }
}

function wrap(attr, value, content) {
  let span = document.createElement("span");
  span.setAttribute(attr, value);
  let inside = content.cloneNode(true); // deep copy
  span.appendChild(inside);
  return span;
}

実行例(jQuery 使用)
実行例(jQuery 未使用)

(2-5)先祖要素

対象となっている要素の先祖(対象となっている要素を内部に含んでいる)要素を取得します。対象となる要素と同じ種類の(タグ名が同じとか同じ属性を持つ)要素である必要はありません。

メソッド引数機能戻り値
parent()なし親要素(1階層分だけ)を返す。jQuery オブジェクト
parents()なしすべての先祖要素(直近の親から遠い方に向かってすべての階層)を返す。jQuery オブジェクト
parentsUntil([終了条件]
         [,選択条件])
終了条件:セレクタ、DOM要素
選択条件:セレクタ(注)
直近の親から遡って検査し、終了条件に一致するまでの要素をすべて返す(一致した要素は含まれない)。ただし、選択条件が指定されている場合はそれに一致する要素のみを返す。jQuery オブジェクト
closest(選択条件
        [, 検索範囲])
選択条件:セレクタ、DOM 要素、jQuery オブジェクト
検索範囲:DOM 要素(注)
指定された条件に合う、対象となっている要素を含めた最も近い先祖要素を返す。ただし、検索範囲が指定されていたらその範囲内のみ検索jQuery オブジェクト
offsetParent()なし先祖方向に調査し position(relative、absolute、fixed)が設定された直近の要素を返す。jQuery オブジェクト
注)セレクタ、DOM要素などに関しては、13.1.3 jQuery オブジェクトの生成 参照

○ parent、parents、parentsUntil、closest

id='d' の要素から先祖要素を検索しています。下の例では、取り出された先祖要素を タグ名(id) の形式で表示しています。

4番目の例は id='a' の要素を探します。結果として U 要素が見つかります。それに対して5番目の例も同様に id='a' の要素を探しますが、検索範囲が id='c' の要素の中なので見つからず何も表示されていません。

記述例
<u id="a">A <i>B <b id="c">C <span id="d">D</span></b></i></u><br>

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

<script>
var p = $("#d").parent();
d01.textContent = disp(p);          // B(c)
p = $("#d").parents();
d02.textContent = disp(p);          // B(c)→I→U(a)→BODY→HTML
p = $("#d").parentsUntil("body");
d03.textContent = disp(p);          // B(c)→I→U(a)
p = $("#d").parentsUntil("body", "[id]");
d04.textContent = disp(p);          // B(c)→U(a)
p = $("#d").closest("[id='a']");
d05.textContent = disp(p);          // U(a)
p = $("#d").closest("[id='a']", c);          // c は id='c' の DOM 要素
d06.textContent = disp(p);          // (表示なし)

function disp(p) {
  let s = "";
  let arrow = "";
  for (let i = 0 ; i < p.length ; i++) {
    s += arrow + p[i].tagName + (p[i].id != "" ? "(" + p[i].id  + ")" : "");
    arrow = "→";
  }
  return s;
}
</script>

上の例の jQuery の記述部分は jQuery を使用しなければ、次のように書き換えることもできます。

なお、[].slice.call は Array.prototype.slice.call と書くこともでき、querySelectorAll などの戻り値を Array オブジェクトに変換します。

var p = d.parentNode;
d01.textContent = disp(p);
p = parents(d);
d02.textContent = disp(p);
var end = document.querySelector("body");
p = parents(d, end);
d03.textContent = disp(p);
p = parents(d, end, document.querySelectorAll("[id]"));
d04.textContent = disp(p);
var target = document.querySelector("[id='a']");
p = closest(d, target);
d05.textContent = disp(p);
p = closest(d, target, c);          // c は id='c' の DOM 要素
d06.textContent = disp(p);

function parents(e, end, select) {
  if (e.parentElement != null) {
    if (select != undefined)
      select = [].slice.call(select);
    return parentsLoop(e.parentElement, end, select);
  }
  else {
    return [];
  }
}
function parentsLoop(e, end, select) {
  let parent = e.parentElement;
  if (parent != null && parent != end) {
    if (select != undefined && select.indexOf(e) < 0)
      return parentsLoop(parent, end, select);
    else
      return [e].concat(parentsLoop(parent, end, select));
  }
  else {
    return (select != undefined && select.indexOf(e) < 0) ? [] : [e];
  }
}

function closest(e, target, range) {
  if (e == range || e == null)
    return [];
  if (e == target)
    return e;
  return closest(e.parentElement, target, range)
}

function disp(p) {
  let s = "";
  if (p instanceof Array) {
    let arrow = "";
    for (let i = 0 ; i < p.length ; i++) {
      s += arrow + p[i].tagName + (p[i].id != "" ? "(" + p[i].id  + ")" : "");
      arrow = "→";
    }
  }
  else {
    s = p.tagName + (p.id != "" ? "(" + p.id  + ")" : "");
  }
  return s;
}
実行例(jQuery 使用)
実行例(jQuery 未使用)

○ offsetParent

offsetParent は、position(relative、absolute、fixed)が設定された直近の先祖要素を検索します。

下の例の場合は、id="b" の span 要素が position:relative なので、これが検索されます。

記述例
<span id="a" style="position:absolute;">A <span id="b" style="position:relative;">B <span id="c" style="position:static;">C <span id="d">D</span></span></span></span><br>

<span id="d01"></span><br>

<script>
var p = $("#d").offsetParent()[0];
d01.textContent = p.tagName + (p.id != "" ? "(" + p.id  + ")" : "");
</script>

上の例の jQuery の記述部分は jQuery を使用しなければ、次のように書き換えることもできます。

var p = offsetParent(d);
d01.textContent = p.tagName + (p.id != "" ? "(" + p.id  + ")" : "");

function offsetParent(e) {
  if (["absolute","relative","fixed"].indexOf(e.style.position) >= 0)
    return e;
  else
    return offsetParent(e.parentElement)
}
実行例(jQuery 使用)
実行例(jQuery 未使用)

(3) 比較

メソッド引数機能戻り値
is(比較条件)比較条件:セレクタ、DOM要素、jQuery オブジェクト(注)比較条件と比較して一致するかどうかを返す。true:一致する、false:一致しない
is(関数)一致する(true)か、一致しない(false)を返す関数
関数の形式
function([index[, element]])
 index:   要素番号(0~)
 element  DOM 要素
戻り値:  true:一致する、false:一致しない
比較条件と比較して一致するかどうかを返す。true:一致する、false:一致しない
注)セレクタ、DOM要素などに関しては、13.1.3 jQuery オブジェクトの生成 参照

引数で指定した要素と一致するかどうかを調べます。

id="c01" の要素は最初の span 要素で、title="a" なので、次の例のうち前半の4つは true に、後半の4つは false になります。

記述例
<span id="c01" title="a"></span><span id="c02"></span><span id="c03"></span><br>

<span id="d01"></span><br><span id="d02"></span><br><br>
<!-- 以下略 -->

<script>
d01.textContent = $("#c01").is("span:first");
d11.textContent = $("#c01").is(c01);
d21.textContent = $("#c01").is($("span")[0]);
d31.textContent = $("#c01").is(function(i, e){return e.title == "a";});
d02.textContent = $("#c01").is("span:last");
d12.textContent = $("#c01").is(c02);
d22.textContent = $("#c01").is($("span")[1]);
d32.textContent = $("#c01").is(function(i, e){return e.title == "x";});
</script>

上の例の jQuery の記述部分は jQuery を使用しなければ、次のように書き換えることもできます。

d01.textContent = c01 == document.querySelector("span:first-of-type");
d11.textContent = c01 == document.getElementById("c01");
d21.textContent = c01 == document.getElementsByTagName("span")[0];
d31.textContent = c01 == checkTitle(c01, "a");
d02.textContent = c01 == document.querySelector("span:last-of-type");
d12.textContent = c01 == document.getElementById("c02");
d22.textContent = c01 == document.getElementsByTagName("span")[1];
d32.textContent = c01 == checkTitle(c01, "x");

function checkTitle(element, title) {
  return element.title == title;
}
実行例(jQuery 使用)
実行例(jQuery 未使用)

(4) DOM要素

メソッド引数機能戻り値
get([要素番号])要素番号:数値(0~)
(マイナス値だと終端からの位置)
要素番号がなければ要素の集合を配列で返す。引数があればその要素を返す。DOM 要素か、その配列
index([要素])要素:jQuery オブジェクトまたは DOM 要素jQueryオブジェクト内で、引数で指定された要素のインデックス番号を返す。要素番号(0~)
見つからなければ -1
toArray()なしjQuery オブジェクトを DOM 要素の配列にして返す。DOM 要素の配列
注)セレクタ、DOM要素などに関しては、13.1.3 jQuery オブジェクトの生成 参照

○ get

jQuery オブジェクトが持つ要素全てを配列の形で返します。引数が記述されていれば指定した DOM 要素を返します。

記述例
<span>A</span><span>B</span><span>C</span>

<script>
function change(e, i , array) {
  e.style.backgroundColor = ["tomato", "cyan", "yellow"][i];             // 背景色を変更する
}

$("span").get().forEach(change);             // 配列の各要素に対して change を実行する
$("span").get(1).textContent = "X";          // 2番目の span 要素を X にする
$("span").get(-1).textContent = "Z";         // 最後の span 要素を Z にする
</script>

上の例の jQuery の記述部分は jQuery を使用しなければ、次のように書き換えることもできます。

なお、[].slice.call は Array.prototype.slice.call と書くこともでき、querySelectorAll などの戻り値を Array オブジェクトに変換します。

var e = [].slice.call(document.querySelectorAll("span"));       // 配列として取り出す
e.forEach(change);
e[1].textContent = "X";
e[e.length-1].textContent = "Z";

実行例(jQuery 使用)
実行例(jQuery 未使用)

○ index

jQuery オブジェクト内で、引数で指定された要素のインデックス番号を返します。見つからなければ -1 になります。

記述例
<span id="a">A</span><span style="color:red;">B</span><span class="x">C</span>
<div id="d1"></div>
<!-- 以下略 -->

<script>
d1.textContent = $("span").index($("span[style*=color]"));      // style="color: ... " のある span 要素の位置
d2.textContent = $("span").index($(".x"));                      // class="x" のある span 要素の位置
d3.textContent = $("span").index($("#a"));                      // id="a" のある span 要素の位置
d4.textContent = $("span").index($(".z"));                      // class="z" のある span 要素の位置
</script>

上の例の jQuery の記述部分は jQuery を使用しなければ、次のように書き換えることもできます。

なお、[].slice.call は Array.prototype.slice.call と書くこともでき、querySelectorAll などの戻り値を Array オブジェクトに変換します。

var e = [].slice.call(document.querySelectorAll("span"), 0);       // 配列として取り出す
d1.textContent = e.indexOf(document.querySelector("span[style*=color]"));
d2.textContent = e.indexOf(document.querySelector(".x"));
d3.textContent = e.indexOf(document.querySelector("#a"));
d4.textContent = e.indexOf(document.querySelector(".z"));

実行例(jQuery 使用)
実行例(jQuery 未使用)

○ toArray

jQuery オブジェクトを DOM要素の配列として返す。

記述例
<span id="a">A</span><span style="color:red;">B</span><span class="x">C</span>
<div id="d1"></div>
<!-- 以下略 -->

<script>
var array = $("span").toArray();
d1.textContent = array[0].textContent + " " + array[0].id;
d2.textContent = array[1].textContent + " " + array[1].style.color;
d3.textContent = array[2].textContent + " " + array[2].className;
</script>

上の例の jQuery の記述部分は jQuery を使用しなければ、次のように書き換えることもできます。

なお、[].slice.call は Array.prototype.slice.call と書くこともでき、querySelectorAll などの戻り値を Array オブジェクトに変換します。

var array = [].slice.call(document.querySelectorAll("span"), 0);
d1.textContent = array[0].textContent + " " + array[0].id;
d2.textContent = array[1].textContent + " " + array[1].style.color;
d3.textContent = array[2].textContent + " " + array[2].className;

実行例(jQuery 使用)
実行例(jQuery 未使用)

(5) 実行

メソッド引数機能戻り値
each(関数)関数
関数の形式
function(index, element)
 index:   要素番号(0~)
 element: DOM 要素
戻り値:  true:処理を継続、false:処理を中断
jQuery オブジェクトに合致する要素に対して順に関数を実行する。
関数が false を返すと途中でも終了する。
jQuery オブジェクト
map(関数)関数
関数の形式
function(index, element)
 index:   要素番号(0~)
 element: DOM 要素
戻り値:  jQuery オブジェクト
jQuery オブジェクトに合致する要素に対して順に関数を実行する。jQuery オブジェクト
注)セレクタ、DOM要素などに関しては、13.1.3 jQuery オブジェクトの生成 参照

○ each

jQuery オブジェクトに合致する要素に対して順に関数を実行します。

関数が false を返すと繰り返しが終了します。

下の例は、span 要素の背景色を黄色にしています。ただし、span 要素内の文字列が空文字列であれば、そこで繰り返しを終了しています。

記述例
<span>AAA</span><span>BBB</span><span>CCC</span><span></span><span>EEE</span>

<script>
$("span").each(function(i, e) {   // span 要素を順に e に取り出す
  if (e.textContent == "") return false;   // 空文字列だと繰り返しをやめる
  e.style.backgroundColor = "yellow";
  return true;
});
</script>

上の例の jQuery の記述部分は jQuery を使用しなければ、次のように書き換えることもできます。

なお、[].slice.call は Array.prototype.slice.call と書くこともでき、querySelectorAll などの戻り値を Array オブジェクトに変換します。

また、some は、true を返す要素があるかどうかを検査します。したがって、結果的に true が1回でも返るとそこで繰り返しが終了します。

var e = [].slice.call(document.querySelectorAll("span"));
e.some(function(e, i) {
  if (e.textContent == "") return true;   // 空文字列だと繰り返しをやめる
  e.style.backgroundColor = "yellow";
  return false;
});

実行例(jQuery 使用)
実行例(jQuery 未使用)

○ map

jQuery オブジェクトに合致する要素に対して順に関数を実行します。

下の例は、span 要素内の文字列に "e" が含まれていたら、span 要素の背景色を黄色にしています。

記述例
<span>one</span><span>two</span><span>three</span><span>four</span><span>five</span>

<script>
$("span").map(function(i, e) {   // span 要素を順に e に取り出す
  if (e.textContent.indexOf("e") >= 0) {
    return e;   // "e" が含まれていたら span 要素を返す
  }
}).css("background-color", "yellow");
</script>

上の例の jQuery の記述部分は jQuery を使用しなければ、次のように書き換えることもできます。

なお、[].slice.call は Array.prototype.slice.call と書くこともでき、querySelectorAll などの戻り値を Array オブジェクトに変換します。

var e = [].slice.call(document.querySelectorAll("span"));
e.filter(function(e, i) {
  if (e.textContent.indexOf("e") >= 0) {
    return e;   // "e" が含まれていたら span 要素を返す
  }
}).forEach(function(e) { e.style.backgroundColor = "yellow"; });

実行例(jQuery 使用)
実行例(jQuery 未使用)

13.3.3  属性(Attributes)

要素の属性に関する処理

(1)属性

HTML に記述されている属性値を操作する場合に使用します。

ただし、取得できる属性値はあくまで記述されている属性値です。例えば、input 要素の checked 属性のような値が変わる可能性のある属性も取得できるのは最初に記述してあった属性値です。

したがって、変化した属性値を取得したい場合は、「(1-3)プロパティ 」を参考にしてください。

メソッド引数機能戻り値
attr(属性名)参照したい属性名属性値を取得する。属性値(文字列)
存在しない属性名を指定すると
undefined
attr(属性名,)属性値を設定したい属性名
属性に設定する値
属性に値を設定する
(存在しない属性名も指定できる)
jQuery オブジェクト
attr(属性)属性名と属性に設定する値からなるオブジェクト
  {
    属性名: 値,
    属性名: 値,
    :
    属性名: 値
  }
属性に値を設定する
(存在しない属性名も指定できる)
jQuery オブジェクト
attr(属性名,関数)属性値を設定したい属性名
属性値を返す関数
関数の形式
function(index[,attr])
 index:   要素番号(0~)
 attr:    変更前の属性値
戻り値:  属性値
属性に値を設定する(存在しない属性名も指定できる) jQuery オブジェクト
removeAttr(属性名)削除したい属性名(空白区切りで複数指定できる)属性を削除する。jQuery オブジェクト

○ attr

DOM要素に属性値を設定したり取得したりします。ただし、取得できる属性値は HTML に記述されている最初の状態の値です。

記述例
<span id="d01"></span> <span id="d02">GREEN</span><br>
<span id="c01">RED</span> <span id="c02">GREEN</span><br>
<div id="c11"><span>RED</span> <span>GREEN</span> <span>BLUE</span></div>

<script>
d01.textContent = $("#c01").attr("id");
d02.textContent = $("#c02").attr("lang");  // 存在しない属性名
$("#c01").attr("style", "color:red");
$("#c02").attr({style:"color:green",title:"オブジェクトでの設定"});
$("#c11 span").attr("style", function(i){return "color:" + ["red","green","blue"][i];});
</script>

上の例の jQuery の記述部分は jQuery を使用しなければ、次のように書き換えることもできます。

存在しない属性名の属性値は空白になるようです(二番目の結果が異なります)。

なお、[].slice.call は Array.prototype.slice.call と書くこともでき、querySelectorAll などの戻り値を Array オブジェクトに変換します。

function setAttribute(e, map) {
  for(let k in map) {
    e.setAttribute(k, map[k]);
  }
}
d01.textContent = c01.getAttribute("id");
d02.textContent = c02.getAttribute("lang");  // 存在しない属性名
c01.setAttribute("style", "color:red");
setAttribute(c02, {style:"color:green",title:"オブジェクトでの設定"});
var e = [].slice.call(document.querySelectorAll("#c11 span"));
e.forEach(function(e, i){e.setAttribute("style", "color:" + ["red","green","blue"][i]);});
実行例(jQuery 使用)
実行例(jQuery 未使用)

attr は HTML に記述されている属性値を返しますが、prop は、実行したときの属性値を返します。

記述例
<input type="checkbox" id="check1" name="" checked="checked" onchange="changed('1')"> <!-- checkedあり -->
<input type="checkbox" id="check2" name="" onchange="changed('2')"><br>               <!-- checkedなし -->
<span id="d11"></span> <span id="d12"></span><br>
<span id="d21"></span> <span id="d22"></span><br>

<script>
changed("1");
changed("2");

function changed(no) {
  document.getElementById("d1" + no).textContent = $("#check" + no).attr("checked");
  document.getElementById("d2" + no).textContent = $("#check" + no).prop("checked");
}
</script>
実行例(attr と prop の違い)

○ removeAttr

DOM要素から属性を削除します。

記述例
<span id="d01" style="color:red;" hidden>RED</span><br>       // hidden を削除するので表示される
<span id="d02" style="color:red;" lang="en"><q>BLACK</q></span><br>  // BLACK と表示される

<script>
$("#d01").removeAttr("hidden");
$("#d02").removeAttr("lang style xxx");
</script>

上の例の jQuery の記述部分は jQuery を使用しなければ、次のように書き換えることもできます。

function removeAttr(e, x) {
  let xList = x.replace(/ \s+/g," ").split(" ");
  for(let i in xList) {
    if (e.hasAttribute(xList[i])) e.removeAttribute(xList[i]);
  }
}
removeAttr(d01, "hidden");
removeAttr(d02, "lang style xxx");
実行例(jQuery 使用)
実行例(jQuery 未使用)

(2)プロパティ

HTML に記述がなくても、要素ごとに持っている値があります。ここでは、それをプロパティと呼ぶことにしその値をプロパティ値としています。そのプロパティ値を操作する場合に使用します。

attr で取得できる属性値も取得できますが、prop で取得できる値は実行したときの属性値です。例えば、select 要素の selectedIndex プロパティのような、ユーザの操作によって値が変わるプロパティ値は、取得しようとしたときの値を取得できます(それに対して、attr では HTML に記述されている値が取得できます)。

したがって、input 要素のプロパティ値を取得する場合は、attr ではなく prop が良いでしょう。

メソッド引数機能戻り値
prop(プロパティ名)参照したいプロパティ名プロパティ値を取得する。プロパティ値(文字列)
存在しないプロパティ名を指定すると
undefined
prop(プロパティ名,)プロパティ値を設定したいプロパティ名
プロパティに設定する値
プロパティに値を設定する
(存在しないプロパティ名も指定できる)
jQuery オブジェクト
prop(プロパティ)プロパティ名とプロパティに設定する値からなるオブジェクト
  {
    プロパティ名: 値,
    プロパティ名: 値,
    :
    プロパティ名: 値
  }
プロパティに値を設定する
(存在しないプロパティ名も指定できる)
jQuery オブジェクト
prop(プロパティ名,関数)プロパティ値を設定したいプロパティ名
プロパティ値を返す関数
関数の形式
function(index[,attr])
 index:   要素番号(0~)
 attr:    変更前のプロパティ値
戻り値:  プロパティ値
プロパティに値を設定する(存在しないプロパティ名も指定できる) jQuery オブジェクト
removeProp(プロパティ名)削除したいプロパティ名プロパティを削除する。注1jQuery オブジェクト
注1)機能しないかもしれない

○ prop

DOM要素にプロパティ値を設定したり取得したりします。ただし、取得できるプロパティ値は HTML に書かれていた値ではなく現状の値です。

記述例
<input type="checkbox" id="check" name="" onchange="changed1()">   <-- checkbox -->
<select id="select" name="" onchange="changed2()"><br>             <-- select -->
 <option value="1">AAA</option>
 <option value="2">BBB</option>
 <option value="3">CCC</option>
 <option value="4">DDD</option>
 <option value="5">EEE</option>
</select><br>
<span id="d01"></span> <span id="d02"></span><br>

<script>
$("#check").prop("checked", true);          // チェックを表示
$("#select").prop({selectedIndex: 1});      // BBB を表示
$("option").prop("disabled", function(i){ if (i==2 || i==4) return "disabled"; });  // 3番目と5番目は選択不可
changed1();
changed2();

function changed1() {
  d01.textContent = $("#check").prop("checked");
}
function changed2() {
  d02.textContent = $("#select").prop("selectedIndex");
}
</script>

上の例の jQuery の記述部分は jQuery を使用しなければ、次のように書き換えることもできます。

なお、[].slice.call は Array.prototype.slice.call と書くこともでき、querySelectorAll などの戻り値を Array オブジェクトに変換します。

check.checked = true;        // チェックを表示
select.selectedIndex = 1;    // BBB を表示
var e = [].slice.call(document.querySelectorAll("option"));
e.forEach(function(e, i){ if(i==2 || i==4) e.disabled=true; });  // 3番目と5番目は選択不可
changed1();
changed2();

function changed1() {
  d01.textContent = check.checked;
}
function changed2() {
  d02.textContent = select.selectedIndex;
}
実行例(jQuery 使用)
実行例(jQuery 未使用)

○ removeProp

DOM要素からプロパティを削除します。

ただし、checked、disabled、selected など、無くなってしまっては困るようなプロパティには使用すべきではありませんし、また(たぶん)機能しません。

これらのプロパティに対しては、prop によって false を設定するようにします。

注意

removeProp は機能していないかもしれません。
checked、disabled、selected だけではなく、data-* のような独自属性も削除できません。

記述例
<button>入力可</button>
<input type="text" disabled />
<script>
$("button").click(function(){
  $("input").removeProp("disabled");  // ボタンをクリックすると disabled が削除される
})
</script>

[入力可]のボタンをクリックすると、入力欄が使用できるようになるはずですが、そうなりません。

実行例(jQuery 使用)

(3)value値

value値の取得、設定を行います。

メソッド引数機能戻り値
val()なしvalue値を取得する。
checkbox最初の要素の value 属性値
radio最初の要素の value 属性値
select選択されている要素の value 属性値
select multiple選択されているすべて要素の
, 区切りの value 属性値
text など最初の要素の value 属性値
val()設定する値value値を設定する
checkbox
 配列内の値に一致する value 属性値を持つ要素にチェックがつく
radio
 配列内の値の最大値に一致する value 属性値を持つ要素にチェックがつく
select
 指定された値に一致する value 属性値を持つ要素が選択される
select multiple
 配列内の値に一致する value 属性値を持つ要素が選択される
text など
 指定された値が value 属性値として設定される
jQuery オブジェクト
val(関数)値を返す関数
関数の形式
function(index[,value])
 index:   要素番号(0~)
 value:   値
value値を設定する(存在しないプロパティ名も指定できる) jQuery オブジェクト

DOM要素に value 値を設定したり取得したりします。

ただし、checkbox と radio で取得できる value値は、checked とは関係なく最初の要素のものになります。

記述例
<input type="text" id="text" name="" size="5"><span id="d01"></span><br>   <-- text -->
<input type="checkbox" id="check1" name="check" value="AAA">
<input type="checkbox" id="check2" name="check" value="BBB">
<input type="checkbox" id="check3" name="check" value="CCC"><span id="d02"></span><br>   <-- checkbox -->
<input type="radio" name="radio" value="1">
<input type="radio" name="radio" value="2">
<input type="radio" name="radio" value="3">
<input type="radio" name="radio" value="4">
<input type="radio" name="radio" value="5"><span id="d03"></span><br>   <-- checkbox -->
<select id="select1" name="">             <-- select -->
 <option value="1">AAA</option>
 <option value="2">BBB</option>
 <option value="3">CCC</option>
</select><span id="d04"></span><br>
<select id="select2" name="" size="3" multiple>             <-- select -->
 <option value="1">AAA</option>
 <option value="2">BBB</option>
 <option value="3">CCC</option>
</select><span id="d05"></span><br>
<progress id="progress" max="100" style="width:100px;"></progress><span id="d06"></span><br>

<script>
$("#text").val("val");                        // text に値設定
d01.textContent = $("#text").val();           // 値表示
$("input[name='check']").val(["CCC","BBB"]);  // 一致する value の checkbox にチェックが付く
d02.textContent = $("input[type='checkbox']").val();  // checked とは関係なく最初の value
$("input[name='radio']").val(["3","4","2"]);          // 一番大きな数値が設定される
d03.textContent = $("input[name='radio']").val();     // checked とは関係なく最初の value
$("#select1").val(3);                 
d04.textContent = $("#select1").val();                // 選択された要素の番号
$("#select2").val([1,3]);                             // 配列で設定
d05.textContent = $("#select2").val();                // 選択されたすべての要素の番号(, 区切り)
$("#progress").val(function() { return (+new Date()) % 100; });     // 関数で設定
d06.textContent = $("#progress").val();
</script>

上の例の jQuery の記述部分は jQuery を使用しなければ、次のように書き換えることもできます。

ここでは、checkbox と radio でも checked されているすべての要素の value 値を取得するようにしています(二番目と三番目の結果が異なります)。

なお、[].slice.call は Array.prototype.slice.call と書くこともでき、querySelectorAll などの戻り値を Array オブジェクトに変換します。

text.value = "val";
d01.textContent = text.value;           // 値表示
var eList = [].slice.call(document.querySelectorAll("input[name='check']"));
eList.forEach(function(e) { setAttr(e, "checked", ["CCC","BBB"]); }); // 一致するvalueの要素にチェックが付く
d02.textContent = getValue(eList, "checked");
eList = [].slice.call(document.querySelectorAll("input[name='radio']"));
eList.forEach(function(e) { setAttr(e, "checked", ["3","4","2"]); }); // 一致するvalueの要素にチェックが付く
d03.textContent = getValue(eList, "checked");
select1.value = 3;
d04.textContent = select1.value;              // 選択された要素の番号
var options = [].slice.call(select2.childNodes);
options.forEach(function(o) { setAttr(o, "selected", [1,3]); });
d05.textContent = getValue(options, "selected");              // 選択されたすべての要素の番号(, 区切り)
progress.value = getProgress();   // 関数で設定
d06.textContent = progress.value;

function setAttr(e, attr, vList) {
  for(let i in vList) {
    if(e.value == vList[i]) {
      e[attr] = true;
      return;
    }
  }
  e[attr] = false;
}
function getValue(eList, attr) {
  let v = "";
  for(let i in eList) {
    if(eList[i][attr] == true)
      v += "," + eList[i].value;
  }
  return v.substring(1);
}
function getProgress() {
  return (+new Date()) % 100;
}
実行例(jQuery 使用)
実行例(jQuery 未使用)

13.3.4  データ(Data)

DOM 要素にデータを一時的に保持、取得させる処理

DOM 要素内に jQuery と22桁の数字からなる名前のオブジェクトが生成され、その中に指定されたプロパティ名で一時的にデータの保存、あるいは取得をします。

ただし、取得する場合には、一時的なデータがなくても 、dataset 内に独自データ属性が存在すれば、独自データの属性値を取得します。

独自データ属性については、「2.3 独自データ属性」を参照してください。

(1)データ

メソッド引数機能戻り値
data(プロパティ名)参照したいプロパティ名プロパティ値を取得する。プロパティ値(文字列)
存在しないプロパティ名を指定すると
undefined
data(プロパティ名,)プロパティ値を設定したいプロパティ名
プロパティに設定する値
プロパティに値を設定する
(存在しないプロパティ名も指定できる)
jQuery オブジェクト
data()なしプロパティ名とプロパティに設定する値
からなるオブジェクト
  {
    プロパティ名: 値,
    プロパティ名: 値,
    :
    プロパティ名: 値
  }
を取得する。
プロパティ名とプロパティに設定する値
からなるオブジェクト
data(プロパティ)プロパティ名とプロパティに設定する値
からなるオブジェクト
プロパティに値を設定する
(存在しないプロパティ名も指定できる)
jQuery オブジェクト
removeData([プロパティ名])削除したいプロパティ名(, 区切りで複数指定できる)
あるいは削除したいプロパティ名の配列
指定されたプロパティを削除する
引数がない場合はすべての削除する
jQuery オブジェクト
$.hasData(DOM 要素)データがあるかどうかを調べたい DOM 要素データがあるかどうかを調べるtrue:存在する、false:存在しない

○ data

DOM 要素の一時的なオブジェクトにデータを設定したり取得したりします。

ただし、data と attr ではデータの保存されるプロパティが異なるので、data で設定した値を attr で取得することはできません(三番目の例)。

記述例
<span id="c01"></span><br>

<span id="d01"></span><br>
<span id="d11"></span> <span id="d12"></span> <span id="d13"></span><br>
<span id="d21"></span><br>

<script>
$("#c01").data("a", "AAA");
d01.textContent = $("#c01").data("a");
$("#c01").data({b:"BBB",c:"CCC"});              // 追加
var data = $("#c01").data();
d11.textContent = data.a;
d12.textContent = data.b;
d13.textContent = data.c;
d21.textContent = $("#c01").attr("data-a");
</script>

上の例の jQuery の記述部分は jQuery を使用しなければ、次のように書き換えることもできます。

ただし、data() では DOM 要素の jQuery と22桁の数字からなる名前のオブジェクト内に保存されますが、ここでは、独自データ属性(data- で始まる属性)と同じく dataset に保存するようにしています。そのため、独自データ属性と同じく data- に続いて指定された名前からなる属性名でも参照することができます(三番目の結果が異なります)。

setData(c01, {a:"AAA"});
d01.textContent = getData(c01, "a");
setData(c01, {b:"BBB",c:"CCC"});              // 追加
var data = getData(c01);
d11.textContent = data.a;
d12.textContent = data.b;
d13.textContent = data.c;
d21.textContent = c01.getAttribute("data-a");

function setData(e, attr) {
  for(let k in attr) {
    e.dataset[k] = attr[k];
  }
}
function getData(e, attr) {
  if (attr != undefined) {
    return e.dataset[attr];        // attr の指定があればその属性のみ
  }
  else {
    return e.dataset;              // attr の指定がなければすべての属性
  }
}
実行例(jQuery 使用)
実行例(jQuery 未使用)

独自データ属性(data- で始まる属性)は、attr でも data でも変更することができます。

ただし、attr は、独自データ属性の属性値そのものを変更するのに対して、data は、別の名前の属性を変更するだけです。したがって、attr で変更すれば attr でも data でも変更された値を取得することができますが、data で変更した場合は attr ではその変更した値を取得することはできません。

○ data("xxx", 属性値) では、jQuery と22桁の数字からなる名前のオブジェクト内に xxx という名前で生成される

○ attr("data-xxx", 属性値) では、 dataset 内に xxx という名前で生成される

記述例
<span id="c01" data-a="xxx"></span><span id="c02"></span>
<span id="c03" data-a="xxx"></span><span id="c04"></span>
<span id="d01"></span> <span id="d02"></span> <span id="d03"></span> <span id="d04"></span><br>
<span id="d11"></span> <span id="d12"></span> <span id="d13"></span> <span id="d14"></span><br>

<script>
$("#c01").data("a", "AAA");
$("#c02").data("a", "AAA");
d01.textContent = $("#c01").attr("data-a");   // data-a あり、data("a", "AAA")、attr("data-a")
d02.textContent = $("#c02").attr("data-a");   // data-a なし、data("a", "AAA")、attr("data-a")
d11.textContent = $("#c01").data("a");        // data-a あり、data("a", "AAA")、data("a")
d12.textContent = $("#c02").data("a");        // data-a なし、data("a", "AAA")、data("a")
$("#c03").attr("data-a", "AAA");
$("#c04").attr("data-a", "AAA");
d03.textContent = $("#c03").attr("data-a");   // data-a あり、attr("data-a", "AAA")、attr("data-a")
d04.textContent = $("#c04").attr("data-a");   // data-a なし、attr("data-a", "AAA")、attr("data-a")
d13.textContent = $("#c03").data("a");        // data-a あり、attr("data-a", "AAA")、data("a")
d14.textContent = $("#c04").data("a");        // data-a なし、attr("data-a", "AAA")、data("a")
</script>

data で変更した場合は attr ではその変更した値を取得することはできません。

実行例

○ removeData

DOM 要素の一時的なオブジェクトからデータを削除します。

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

<script>
$("#c01").data({a:"AAA",b:"BBB",c:"CCC"});
show(d01, d02, d03, c01);

$("#c01").removeData("a");                  // a を削除
show(d11, d12, d13, c01);

$("#c01").data({a:"AAA",b:"BBB",c:"CCC"});
$("#c01").removeData("a c");                // a と c を削除(空白区切りの文字列)
show(d21, d22, d23, c01);

$("#c01").data({a:"AAA",b:"BBB",c:"CCC"});
$("#c01").removeData(["a", "b"]);           // a と b を削除(配列)
show(d31, d32, d33, c01);

$("#c01").data({a:"AAA",b:"BBB",c:"CCC"});
$("#c01").removeData();                     // すべてを削除
show(d41, d42, d43, c01);

function show(d1, d2, d3, c) {
  let data = $("#" + c.id).data();
  d1.textContent = data.a;
  d2.textContent = data.b;
  d3.textContent = data.c;
}
</script>

上の例の jQuery の記述部分は jQuery を使用しなければ、次のように書き換えることもできます。

なお、setData や getData については、○ data の例を参照してください。

setData(c01, {a:"AAA",b:"BBB",c:"CCC"});
show(d01, d02, d03, c01);

removeData(c01, "a");                       // a を削除
show(d11, d12, d13, c01);

setData(c01, {a:"AAA",b:"BBB",c:"CCC"});
removeData(c01, "a c");                     // a と c を削除(空白区切りの文字列)
show(d21, d22, d23, c01);

setData(c01, {a:"AAA",b:"BBB",c:"CCC"});
removeData(c01, ["a", "b"]);                // a と b を削除(配列)
show(d31, d32, d33, c01);

setData(c01, {a:"AAA",b:"BBB",c:"CCC"});
removeData(c01);                            // すべてを削除
show(d41, d42, d43, c01);

function removeData(e, attr) {
  if (attr == undefined) {
    for(let i in e.dataset) {
      delete e.dataset[i];
    }
  }
  else if (typeof attr == "string") {
    let aList = attr.replace(/ \s+/g," ").split(" ");
    for(let i in aList) {
      if (e.dataset[aList[i]] != undefined) delete e.dataset[aList[i]];
    }
  }
  else if (Array.isArray(attr)) {
    for(let i in attr) {
      if (e.dataset[attr[i]] != undefined) delete e.dataset[attr[i]];
    }
  }
}
function show(d1, d2, d3, c) {
  let data = getData(c);
  d1.textContent = data.a;
  d2.textContent = data.b;
  d3.textContent = data.c;
}
実行例(jQuery 使用)
実行例(jQuery 未使用)

○ hasData

DOM 要素にデータが存在するかどうかを調べます。ただし、独自データ属性(data- で始まる属性名)は対象外です。

また、jQuery ではイベントハンドラが設定されるとデータとして保存されるので、データが無くても true が返ります。

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

<script>
$("#c01").data("a", "AAA");
d01.textContent = $.hasData(c01);
$("#c02").click(function(){});       // イベントハンドラが設定されていると
d02.textContent = $.hasData(c02);    // データがなくても true
$("#c03").attr("x", "XXX");          // 属性を追加しても false
d03.textContent = $.hasData(c03);
</script>

上の例の jQuery の記述部分は jQuery を使用しなければ、次のように書き換えることもできます。

ただし、jQuery の data() や click() では jQuery と22桁の数字からなる名前のオブジェクト内に保存されますが、ここでは、データは独自データ属性と同じ dataset に保存し、イベントハンドラーは onclick に関連付けています。(二番目と三番目の結果が異なります)。

なお、setData については、○ data の例を参照してください。

setData(c01, {a:"AAA"});
d01.textContent = hasData(c01);
d02.textContent = hasData(c02);
c02.onclick = function(){};         // click イベントハンドラは onclick
d02.textContent = hasData(c02);
c03.setAttribute("data-a", "AAA");  // データは dataset
d03.textContent = hasData(c03);

function hasData(e) {
    for(let i in e.dataset) {
      return true;
    }
    return false;
}
実行例(jQuery 使用)
実行例(jQuery 未使用)

13.3.5  スタイルシート(CSS)

スタイルシートの属性やクラスを設定あるいは取得する処理

(1)CSS

スタイルシートの属性を設定あるいは取得する処理

メソッド引数機能戻り値
css(属性名)属性名:文字列(注)指定した属性名の値を取得する。属性値:文字列
css(属性名の配列)属性名:文字列(注)指定した属性名の値を取得する。属性値の配列:文字列
css(属性名, 属性値)属性名:文字列
属性値:文字列
指定した属性名の値を設定する。jQuery オブジェクト
css(属性名, 関数)属性値を返す関数
関数の形式
function(index, value)
 index:   要素番号(0~)
 value:   変更前の属性値
戻り値:  変更したい属性値
指定した属性名の値を設定する。jQuery オブジェクト
css(マップ)マップ:属性名と属性値のマップ指定した属性名の値を設定する。jQuery オブジェクト
注)属性名に "-" がある場合は、そのままの名前(例えば、text-decoration)でも良いですが、"-" をとって "-" の次の文字を大文字にした名前(例えば、textDecoration)でも構いません。

color 属性値は web カラー名ではなく rgb で得られるようです。

また、属性名の配列では、"-" が無い属性名は css.color のように指定できますが、"-" があると減算演算子と見なされてしまいます。よって、この場合は、css["font-style"] のように指定します。

記述例
<span id="d01">RED</span><br>
<span id="d11"><br>
<span id="d02" style="color:blue;">BLUE</span><br>
<span id="d21"></span> <span id="d22"></span> <span id="d23"></span><br>
<div id="d03"><span>RED</span><span>GREEN</span><span>BLUE</span></div>

<script>
$("#d01").css("color", "red");                 // 属性名と属性値を指定して設定
d11.textContent = $("#d01").css("color");      // 属性名を指定して取得
$("#d02").css({"font-style":"italic", "textDecoration":"underline"});         // マップで設定
var css = $("#d02").css(["color","font-style","textDecoration"]);             // 配列で属性名を指定して取得
d21.textContent = css.color;                   // 属性名に "-" が無いとき
d22.textContent = css["font-style"];           // 属性名に "-" が有るとき
d23.textContent = css.textDecoration;
$("#d03 span").css("color", function(i) {return ["red", "green", "blue"][i];});     // 関数で設定
</script>

上の例の jQuery の記述部分は jQuery を使用しなければ、次のように書き換えることもできます。

ここでは、color 属性値は指定されたままを取得するようにしています(二番目と四番目の結果が異なります)。

なお、[].slice.call は Array.prototype.slice.call と書くこともでき、querySelectorAll などの戻り値を Array オブジェクトに変換します。

d01.style.color = "red";                 // 属性名と属性値を指定して設定
d11.textContent = d01.style.color;       // 属性名を指定して取得
setStyle(d02, {"font-style":"italic", "textDecoration":"underline"});    // マップで設定
var css = getStyle(d02, ["color","font-style","textDecoration"]);        // 配列で属性名を指定して取得
d21.textContent = css.get("color");
d22.textContent = css.get("font-style");
d23.textContent = css.get("textDecoration");
var eList = [].slice.call(document.querySelectorAll("#d03 span"));
eList.forEach(function(e, i) { e.style.color = ["red", "green", "blue"][i]; });     // 関数で個別に設定

function setStyle(e, map) {
  for(let key in map) {
    e.style[key] = map[key];
  }
}
function getStyle(e, attrList) {
  let map = new Map();
  for(let key in attrList) {
    let attr = attrList[key];
    map.set(attr, e.style[attr]);
  }
  return map;
}

表示しきれるように、文字を小さくしているところがあります。

実行例(jQuery 使用)
実行例(jQuery 未使用)

(2)クラス

メソッド引数機能戻り値
addClass(クラス名)追加したいクラス名(空白区切りで複数指定できる)要素にクラスを追加する。jQuery オブジェクト
addClass(関数)クラス名を返す関数
関数の形式
function(index[,class])
 index:   要素番号(0~)
 class: 指定済みのクラス名
戻り値:  追加したいクラス名
要素にクラスを追加する。jQuery オブジェクト
hasClass(クラス名)判定したいクラス名注1要素が指定したクラスを持つかどうかを判定する。true:持つ、false:持たない
removeClass(クラス名)削除したいクラス名要素から指定したクラスを削除する。jQuery オブジェクト
toggleClass([クラス名[,switch]])追加・削除したいクラス名注1
(省略時:前回指定したクラス名)
switch が true ならば追加、false ならば削除(省略時:交互)
要素に対して指定したクラスを追加・削除する。jQuery オブジェクト
toggleClass(関数[,switch])クラス名を返す関数
switch が true ならば追加、false ならば削除(関数の第三引数として渡される)(省略時:交互)
関数の形式
function(index[,class[,sw]])
 index: 要素番号(0~)
 class: 指定済みのクラス名
 sw:    true:追加、false:削除
戻り値:  追加・削除したいクラス名
要素に対してクラスを追加・削除する。jQuery オブジェクト
注1)空白区切りで複数指定できるが、class 属性値の部分文字列の必要がある。
   例えば、class="a b c" のとき、"a b" は一致するが、"a   b"、"b a"、"a c" は一致しない
   (removeClass ではどのように指定しても削除できる)

○ addClass

DOM要素にスタイルシートのクラスを追加します。

記述例
<style>
  .c0 { color: red; }
  .c1 { color: green; }
  .c2 { color: blue; }
  .i { font-style: italic; }
  .u { text-decoration: underline; }
</style>
<span id="d01">RED</span><br>
<span id="d02" class="c2">BLUE</span><br>
<div id="d03"><span>RED</span><span>GREEN</span><span>BLUE</span></div>

<script>
$("#d01").addClass("c0");
$("#d02").addClass("i u");
$("#d03 span").addClass(function(i) {return "c" + i;});
</script>

上の例の jQuery の記述部分は jQuery を使用しなければ、次のように書き換えることもできます。

なお、[].slice.call は Array.prototype.slice.call と書くこともでき、querySelectorAll などの戻り値を Array オブジェクトに変換します。

function addClass(e, x) {
  let cList = e.className.replace(/ \s+/g," ").split(" ");
  let xList = x.replace(/ \s+/g," ").split(" ");
  for(let i in xList) {
    if(cList.indexOf(xList[i]) < 0) {
      cList.push(xList[i]);
    }
  }
  e.className = cList.join(" ");
}
addClass(d01, "c0");
addClass(d02, "i u");       // 指定されているクラス名に追加して設定する
var e = [].slice.call(document.querySelectorAll("#d03 span"));
e.forEach(function(e, i){ addClass(e, "c" + i); });

実行例(jQuery 使用)
実行例(jQuery 未使用)

○ hasClass

指定したクラス名が割り当てられているかどうかを判定します。

クラス名は空白で区切って複数指定できるようですが、クラス属性で指定されているクラス名の部分文字列でないと正しく判断されないようです。例えば、空白の数が違っていたりクラス名の順番が異なっていると、存在するクラス名を指定しても false となります。

記述例
<span id="c1" class="a"></span><br>
<span id="c2" class="a b c"></span><br>
<span id="d01"></span><span id="d02"></span><br>
<span id="d11"></span><span id="d12"></span><br>

<script>
$("#d01").text($("#c1").hasClass("a"));    // true
$("#d02").text($("#c1").hasClass("b"));    // false
$("#d11").text($("#c2").hasClass("a b"));  // true
$("#d12").text($("#c2").hasClass("a c"));  // false("a b c" の部分文字列でないと true にならない)
</script>

上の例の jQuery の記述部分は jQuery を使用しなければ、次のように書き換えることもできます。

ここでは、クラス名の順番などが異なっていても正しく判断するようにしています(四番目の結果が異なります)。

function hasClass(e, x) {
  let cList = e.className.replace(/ \s+/g," ").split(" ");
  let xList = x.replace(/ \s+/g," ").split(" ");
  for(let i in xList) {
    if(cList.indexOf(xList[i]) < 0) return false;
  }
  return true;
}
d01.textContent = hasClass(c1, "a");
d02.textContent = hasClass(c1, "b");
d11.textContent = hasClass(c2, "a b");
d12.textContent = hasClass(c2, "a c");

実行例(jQuery 使用)
実行例(jQuery 未使用)

○ removeClass

DOM要素からスタイルシートのクラスを削除します。

記述例
<style>
  .r { color: red; }
  .g { color: green; }
  .b { color: blue; }
  .i { font-style: italic; }
  .u { text-decoration: underline; }
<style>

<span id="d01" class="r i">RED</span><br>
<span id="d02" class="g  i     u">GREEN</span><br>
<span id="d03" class="b u"><span>BLUE</span><br>

<script>
$("#d01").removeClass("i");
$("#d02").removeClass("i  u");
$("#d03").removeClass("i u");    // i は指定されていない
</script>

上の例の jQuery の記述部分は jQuery を使用しなければ、次のように書き換えることもできます。

function removeClass(e, x) {
  let cList = e.className.replace(/ \s+/g," ").split(" ");
  let xList = x.replace(/ \s+/g," ").split(" ");
  for(let i in xList) {
    let n = cList.indexOf(xList[i]);
    if(n >= 0) cList[n] = "";
  }
  e.className = cList.join(" ");
}
removeClass(d01, "i");
removeClass(d02, "i  u");
removeClass(d03, "i u");

実行例(jQuery 使用)
実行例(jQuery 未使用)

○ toggleClass

DOM要素からスタイルシートのクラスを追加・削除します。

toggleClass の2番目の引数が true ならば追加、false ならば削除になります。

記述例
<style>
  .c0 { color: red; }
  .c1 { color: green; }
  .c2 { color: blue; }
  .i { font-style: italic; }
  .u { text-decoration: underline; }
</style>
<span id="d01" class="i">RED</span> <span id="d02" class="i c2 u">BLUE</span><br>
<div id="d11"><span>RED</span> <span>GREEN</span> <span>BLUE</span></div>

<script>
$("#d01").toggleClass("c0 i", true);  // 追加(i は指定あり)
$("#d02").toggleClass("b i", false);  // 削除(b は指定なし)

function toggle() {
  $("#d11 span").toggleClass(function(i,c) {return "c"+i;}); // それぞれの span 要素へのクラス名の追加・削除を交互にする
}
window.setInterval(toggle, 1000);
</script>

上の例の jQuery の記述部分は jQuery を使用しなければ、次のように書き換えることもできます。

なお、[].slice.call は Array.prototype.slice.call と書くこともでき、querySelectorAll などの戻り値を Array オブジェクトに変換します。

var createSwitch = function() {  // クロージャです(「6.5 クロージャ」を参考にしてください)
  let sw = true;
  return function() {
    sw = !sw;
    return sw;
  }
}
var getSwitch = createSwitch();

function toggleClass(e, x, s) {
  let cList = s.className.replace( \s+/g," ").split(" ");
  let xList = s.replace(/ \s+/g," ").split(" ");
  for(let i in xList) {
    let n = cList.indexOf(xList[i]);
    if (n < 0) {
      if (s) cList.push(xList[i]);  // 追加
    }
    else {
      if (!s) cList[n] = "";        // 削除
    }
  }
  e.className = cList.join(" ");
}

toggleClass(d01, "c0 i", true);  // 追加
toggleClass(d02, "b i", false);  // 削除

function toggle() {
  let sw = getSwitch();  // getSwitch を呼ぶごとに true と false が交互に返る
  let e = [].slice.call(document.querySelectorAll("#d11 span"));
  e.forEach(function(e, i) { toggleClass(e, "c"+i, sw); });
}
window.setInterval(toggle, 1000);

実行例(jQuery 使用)
実行例(jQuery 未使用)

13.3.6  位置とサイズ

DOM 要素の位置や幅、高さを求める処理

(1)位置

DOM 要素の位置を求める処理

メソッド引数機能戻り値
offset()なしdocumentを基準とする座標を取得する。topとleftを含むオブジェクト
offset(座標)座標:設定したい top と left を含むオブジェクトdocumentを基準とする座標を設定する。jQuery オブジェクト
offset(関数)値を返す関数
関数の形式
function(index, coords)
 index:   要素番号(0~)
 coords:  topとleftを含むオブジェクト
戻り値:  変更したい topとleftを含むオブジェクト
documentを基準とする座標を設定するjQuery オブジェクト
position()なし親要素を基準とする座標を取得する。topとleftを含むオブジェクト
scrollLeft()なしスクロール位置(X座標)を取得する。数値
scrollLeft([X座標])X座標:数値スクロールして隠れているような位置(X座標)を指定し表示させる。jQuery オブジェクト
scrollTop()なしスクロール位置(Y座標)を取得する。数値
scrollTop([Y座標])Y座標:数値スクロールして隠れているような位置(Y座標)を指定し表示させる。jQuery オブジェクト

○ offset、position

offset は document を基準とした座標、position は 親要素(下の例では内側の section 要素)を基準とした座標です。

記述例
<style>
div {
  position:absolute; 
  width:40px;
  height:20px;
}
</style>

<section style="position:absolute; top:0px; left:0px;">
 <section style="position:absolute; top:20px; left:40px;">
  <div id="c01" style="top:10px; left:50px; background-color:yellow;">AAA</div>
  <div id="c02" style="top:0px; left:0px; background-color:orange;">BBB</div>
  <div id="c03" style="top:0px; left:100px; background-color:orange;">CCC</div>
 <section>
<section>
<span id="d01"></span> <span id="d02"></span><br>
<span id="d11"></span> <span id="d12"></span><br>

<script>
d01.textContent = $("#c01").offset().top;       // AAA
d02.textContent = $("#c01").offset().left;
d11.textContent = $("#c01").position().top;
d12.textContent = $("#c01").position().left;

$("#c02").offset({ top:30, left:150 });                                     // BBB  top:30, left:150
$("#c03").offset(function(i,e) { e.top = 30; e.left += 70; return e; });   // CCC  top:30, left:170
</script>

上の例の jQuery の記述部分は jQuery を使用しなければ、次のように書き換えることもできます。

なお、スタイルシートへの設定は px、em などの単位が必要です。また、スタイルシートから取得した幅は px という単位が付属します。

d01.textContent = c01.parentNode.offsetTop + c01.offsetTop;
d02.textContent = c01.parentNode.offsetLeft + c01.offsetLeft;
d11.textContent = c01.offsetTop;
d12.textContent = c01.offsetLeft;

offset(c02, { top:30, left:150 });
offset(c03, { top:30, left:c03.parentNode.offsetLeft+c03.offsetLeft+70 });

function offset(e, pos) {
  e.style.top = (pos.top - e.parentNode.offsetTop) + "px";
  e.style.left = (pos.left - e.parentNode.offsetLeft) + "px";
}
実行例(jQuery 使用)

実行例(jQuery 未使用)


○ scrollLeft、scrollTop

section 要素内に div 要素の内容が表示しきれないのでスクロールバーが表示されます。

スクロールさせることによって、表示されている部分が変わり、その位置が得られ枠の中に表示されます。

また、枠の中の数値を変更することによって、スクロールさせることもできます。

記述例
<section id="c01" style="overflow:auto; height:60px; width:200px;" onscroll="disp(this);">
  <div style="background-color:yellow;">1ABCDEFGHIJKLMNOPQRSTUVWXYZ<br>2ABCDEFGHIJKLMNOPQRSTUVWXYZ<br>3ABCDEFGHIJKLMNOPQRSTUVWXYZ<br>4ABCDEFGHIJKLMNOPQRSTUVWXYZ<br>5ABCDEFGHIJKLMNOPQRSTUVWXYZ</div>
</section>

<input id="d01" type="text" value="0" onkeyup="changeTop(this);"/> <input id="d02" type="text" value="0" onkeyup="changeLeft(this);"/>

<script>
function disp(me) {
  d01.value = $("#" + me.id).scrollTop();
  d02.value = $("#" + me.id).scrollLeft();
}
function changeTop(me) {
  $("#c01").scrollTop(me.value);
}
function changeLeft(me) {
  $("#c01").scrollLeft(me.value);
}
</script>

上の例の jQuery の記述部分は jQuery を使用しなければ、次のように書き換えることもできます。

function disp(me) {
  d01.value = me.scrollTop;
  d02.value = me.scrollLeft;
}
function changeTop(me) {
  c01.scrollTop = me.value;
}
function changeLeft(me) {
  c02.scrollLeft = me.value;
}
実行例(jQuery 使用)

実行例(jQuery 未使用)


(2)幅と高さ

DOM 要素の幅や高さを求める処理

メソッド引数機能戻り値
width()なし幅を取得する。幅(px単位)
width()設定したい幅(px単位)幅を設定する。jQuery オブジェクト
width(関数)値を返す関数
関数の形式
function(index[,value])
 index:   要素番号(0~)
 value:   変更前の幅
戻り値:  変更したい幅(px単位)
幅を設定するjQuery オブジェクト
innerWidth()なしpadding 領域を含む要素の幅(border 領域は含まない)を取得する。つまり、要素の内側の幅幅(px単位)
outerWidth([margin])margin 領域を含むかどうか(true:含む)(規定値:false)border 領域を含む要素の幅(引数が true ならば margin 領域を含む)を取得する。つまり、要素の外側の幅幅(px単位)
height()なし高さを取得する。高さ(px単位)
height()設定したい高さ(px単位)高さを設定する。jQuery オブジェクト
height(関数)値を返す関数
関数の形式
function(index[,value])
 index:   要素番号(0~)
 value:   変更前の高さ
戻り値:  変更したい高さ(px単位)
高さを設定するjQuery オブジェクト
innerHeight()なしpadding 領域を含む要素の高さ(border 領域は含まない)を取得する。つまり、要素の内側の高さ高さ(px単位)
outerHeight([margin])margin 領域を含むかどうか(true:含む)(規定値:false)border 領域を含む要素の高さ(引数が true ならば margin 領域を含む)を取得する。つまり、要素の外側の高さ高さ(px単位)

○ width、innerWidth、outerWidth

要素の横幅を px 単位で設定あるいは取得します。

ただし、ブロックレベル形式で表示(初期値として display が block や inline-block などになっているか、そのように変更しているか)していないと正しく設定できないことがあります。

記述例
<style>
div#c01 {
  background-color:lawngreen;
  border-style:solid;
  border-color:limegreen;
}
</style>

<div id="c01" style="margin:30px 50px; padding:25px 35px; border-width:10px 20px;"></div>
<span id="d01"></span><br>
<!-- 以下略 -->

<script>
$("#c01").width(60);                            // div 要素(下の図の背景色が白い XXXXX の部分)の幅を変更
d01.textContent = $("#c01").width();            // div 要素の幅を取得
d11.textContent = $("#c01").innerWidth();       // div 要素の padding を含んだ部分(薄い緑の部分)の幅
d21.textContent = $("#c01").outerWidth(false);  // div 要素の border を含んだ部分(濃い緑の部分)の幅
d22.textContent = $("#c01").outerWidth(true);   // div 要素の margin を含んだ部分(灰色の破線で囲まれた部分の部分)の幅
$("#c01").width(function(){ return 100; });     // 関数で変更
d31.textContent = $("#c01").width();
</script>

上の例の jQuery の記述部分は jQuery を使用しなければ、次のように書き換えることもできます。

なお、スタイルシートへの設定は px、em などの単位が必要です。また、スタイルシートから取得した幅は px という単位が付属します。

c01.style.width = "60px";
var display = c01.style.display;
c01.style.display = "inline-block";     // style.width を指定しないときに最小幅を得るため
var width = parseInt(c01.clientWidth) - (parseInt(c01.style.paddingLeft) + parseInt(c01.style.paddingRight));
c01.style.display = display;
d01.textContent = width;
width += parseInt(c01.style.paddingLeft) + parseInt(c01.style.paddingRight);
d11.textContent = width;
width += parseInt(c01.style.borderLeftWidth) + parseInt(c01.style.borderRightWidth);
d21.textContent = width;
width += parseInt(c01.style.marginLeft) + parseInt(c01.style.marginRight);
d22.textContent = width;
c01.style.width = getWidth();
d31.textContent = parseInt(c01.style.width);

function getWidth() {
  return "100px";
}

c01 は次のように領域がとられます。

実行例(jQuery 使用)
実行例(jQuery 未使用)

○ height、innerHeight、outerHeight

メソッド引数機能戻り値
height()なし高さを取得する。高さ(px単位)
height()設定したい高さ(px単位)高さを設定する。jQuery オブジェクト
height(関数)値を返す関数
関数の形式
function(index[,value])
 index:   要素番号(0~)
 value:   変更前の高さ
戻り値:  変更したい高さ(px単位)
高さを設定するjQuery オブジェクト
innerHeight()なしpadding 領域を含む要素の高さ(border 領域は含まない)を取得する。つまり、要素の内側の高さ高さ(px単位)
outerHeight([margin])margin 領域を含むかどうか(true:含む)(規定値:false)border 領域を含む要素の高さ(引数が true ならば margin 領域を含む)を取得する。つまり、要素の外側の高さ高さ(px単位)

要素の高さを px 単位で設定あるいは取得します。

ただし、ブロックレベル形式で表示(初期値として display が block や inline-block などになっているか、そのように変更しているか)していないと正しく設定できないことがあります。

記述例
<style>
div#c01 {
  width:100px;
  background-color:lawngreen;
  border-style:solid;
  border-color:limegreen;
}
</style>

<div id="c01" style="margin:30px 50px; padding:25px 35px; border-width:10px 20px;"></div>
<span id="d01"></span><br>
<!-- 以下略 -->

<script>
$("#c01").height(40);                            // div 要素(下の図の背景色が白い XXXXX の部分)の高さを変更
d01.textContent = $("#c01").height();            // div 要素の高さを取得
d11.textContent = $("#c01").innerHeight();       // div 要素の padding を含んだ部分(薄い緑の部分)の高さ
d21.textContent = $("#c01").outerHeight(false);  // div 要素の border を含んだ部分(濃い緑の部分)の高さ
d22.textContent = $("#c01").outerHeight(true);   // div 要素の margin を含んだ部分(灰色の破線で囲まれた部分の部分)の高さ
$("#c01").width(function(){ return 100; });      // 関数で変更
d31.textContent = $("#c01").height();
</script>

上の例の jQuery の記述部分は jQuery を使用しなければ、次のように書き換えることもできます。

なお、スタイルシートへの設定は px、em などの単位が必要です。また、スタイルシートから取得した幅は px という単位が付属します。

c01.style.height = "40px";
var display = c01.style.display;
c01.style.display = "inline-block";     // style.height を指定しないときに最小幅を得るため
var height = parseInt(c01.clientHeight) - (parseInt(c01.style.paddingTop) + parseInt(c01.style.paddingBottom));
c01.style.display = display;
d01.textContent = height;
height += parseInt(c01.style.paddingTop) + parseInt(c01.style.paddingBottom);
d11.textContent = height;
height += parseInt(c01.style.borderTopWidth) + parseInt(c01.style.borderBottomWidth);
d21.textContent = height;
height += parseInt(c01.style.marginTop) + parseInt(c01.style.marginBottom);
d22.textContent = height;
c01.style.height = getHeight();
d31.textContent = parseInt(c01.style.height);

function getHeight() {
  return "60px";
}

c01 は次のように領域がとられます。

実行例(jQuery 使用)
実行例(jQuery 未使用)

13.3.7  DOM要素の操作

DOM 要素を操作する処理

(1)兄弟要素の挿入

兄弟要素(同じ階層の DOM 要素)を挿入します。

after、before は引数の要素を挿入するのに対して、insertAfter、insertBefore は、引数で挿入する場所を指定します。

また、after、before で引数にドキュメント上の DOM要素、jQuery オブジェクトを指定すると移動になります(コピーされ挿入されるわけではありません)。

メソッド引数機能戻り値
after(要素[,要素])要素:文字列、DOM要素、jQuery オブジェクト、またはそれらの配列(注)指定の要素を直後に挿入する。jQuery オブジェクト
after(関数)jQuery オブジェクトを返す関数
関数の形式
function(index[, html])
 index:   要素番号(0~)
 html:    変更前の HTML
戻り値:  変更したい HTML
関数が返した要素を直後に挿入する。jQuery オブジェクト
insertAfter(要素)要素:セレクタ、jQuery オブジェクト(注)指定の要素の直後に挿入する。jQuery オブジェクト
before(要素[,要素])要素:文字列、DOM要素、jQuery オブジェクト、またはそれらの配列(注)指定の要素を直前に挿入する。jQuery オブジェクト
before(関数)jQuery オブジェクトを返す関数
関数の形式
function(index[, html])
 index:   要素番号(0~)
 html:    変更前の HTML
戻り値:  変更したい HTML
関数が返した要素を直前に挿入する。jQuery オブジェクト
insertBefore(要素)要素:セレクタ、jQuery オブジェクト(注)指定の要素の直前に挿入する。jQuery オブジェクト
注)セレクタ、DOM要素などに関しては、13.1.3 jQuery オブジェクトの生成 参照

記述例

挿入する要素として、DOM 要素や jQuery オブジェクトを指定すると、ドキュメント上にあったそれらは、コピーされて挿入されるのではなく、移動することになります(二番目と四番目の例)。

<u id="a1">A</u><b id="b1">B</b><i id="c1">C</i><br>
<u id="a2">A</u><b id="b2">B</b><i id="c2">C</i><br>

<span id="d01" style="color:red;">A</span><span>C</span><br>
<span id="d02" style="color:red;">A</span><br>
<span>A</span><span id="d03" style="color:red;">C</span><br>
<span id="d04" style="color:red;">C</span><br>

<script>
$("#d01").after("<b>B</b>");     // A の後ろに B
$("#d02").after([b1,$("#c1")]);  // A の後ろに B、C
$("#d03").before("<b>B</b>");    // C の前に B
$("#d04").before([$("#a2"),b2]); // C の前に A、B
</script>

なお、上の例は次のように書かれていたかのように表示されます。

<u id="a1">A</u><br>
<i id="c2">C</i><br>

<span id="d01" style="color:red;">A</span><b>B</b><span>C</span><br>
<span id="d02" style="color:red;">A</span><b id="b1">B</b><i id="c1">C</i><br>
<span>A</span><b>B</b><span id="d03" style="color:red;">C</span><br>
<u id="a2">A</u><b id="b2">B</b><span id="d04" style="color:red;">C</span><br>

また、上の例の jQuery の記述部分は jQuery を使用しなければ、次のように書き換えることもできます。

var b = document.createElement("b");
b.textContent = "B";
d01.parentNode.insertBefore(b, d01.nextSibling);     // A の後ろに B
var list = [b1, c1];
var nx = d02.nextSibling;
for (let i in list) {
  d02.parentNode.insertBefore(list[i], nx);          // A の後ろに B、C
}
b = document.createElement("b");
b.textContent = "B";
d03.parentNode.insertBefore(b, d03);                 // C の前に B
list = [a2, b2];
for (let i in list) {
  d04.parentNode.insertBefore(list[i], d04);         // C の前に A、B
}
実行例(jQuery 使用)
実行例(jQuery 未使用)

(2)子孫要素の挿入

子孫要素を挿入します。

メソッド引数機能戻り値
append(要素[,要素])要素:文字列、DOM要素、jQuery オブジェクト、またはそれらの配列(注)指定の要素を要素内の最後に挿入する。jQuery オブジェクト
append(関数)jQuery オブジェクトを返す関数
関数の形式
function(index[, html])
 index:   要素番号(0~)
 html:    変更前の HTML
戻り値:  変更したい HTML
関数が返した要素を要素内の最後に挿入する。jQuery オブジェクト
appendTo(要素)要素:セレクタ、DOM要素、jQuery オブジェクト(注)指定の要素の最後の子要素として挿入する。jQuery オブジェクト
prepend(要素[,要素])要素:文字列、DOM要素、jQuery オブジェクト、またはそれらの配列(注)指定の要素を要素内の最初に挿入する。jQuery オブジェクト
prepend(関数)jQuery オブジェクトを返す関数
関数の形式
function(index[, html])
 index:   要素番号(0~)
 html:    変更前の HTML
戻り値:  変更したい HTML
関数が返した要素を要素内の最初に挿入する。jQuery オブジェクト
prependTo(要素)要素:セレクタ、DOM要素、jQuery オブジェクト(注)指定の要素の最初の子要素として挿入する。jQuery オブジェクト
wrapInner(要素)要素:HTML文字列、セレクタ、DOM要素、jQuery オブジェクト(注)要素の内容を指定した要素で囲む。jQuery オブジェクト
wrapInner(関数)jQuery オブジェクトを返す関数
関数の形式
function(index)
 index:   要素番号(0~)
戻り値:  変更したい要素
関数が返した要素の内容を指定した要素で囲む。jQuery オブジェクト
注)セレクタ、DOM要素などに関しては、13.1.3 jQuery オブジェクトの生成 参照

○ append、prepend

指定した要素を、最後あるいは最初の子要素として挿入します。

記述例

挿入する要素として、DOM 要素や jQuery オブジェクトを指定すると、ドキュメント上にあったそれらは、コピーされて挿入されるのではなく、移動することになります(二番目と四番目の例)。

<u id="a1">A</u><b id="b1">B</b><i id="c1">C</i><br>
<u id="a2">A</u><b id="b2">B</b><i id="c2">C</i><br>
<u id="n1">1</u><b id="n2">2</b><i id="n3">3</i><br>
<u id="x1">x</u><b id="x2">y</b><i id="x3">z</i><br>

<span id="d01" style="color:red;">A</span><span>C</span><br>
<span id="d02" style="color:red;">A</span><br>
<span>A</span><span id="d03" style="color:red;">C</span><br>
<span id="d04" style="color:red;">C</span><br>

<span id="d05"><span>A</span><span>B</span><span>C</span></span><br>

<script>
$("#d01").append("<b>B</b>");     // A の後ろに B
$("#d02").append([b1,$("#c1")]);  // A の後ろに B、C
$("#d03").prepend("<b>B</b>");    // C の前に B
$("#d04").prepend([$("#a2"),b2]); // C の前に A、B

$("#d05 span").append(function(i){ return $("#n" + (i+1)); });
$("#d05 span").prepend(function(i){ return document.getElementById("x" + (i+1)); });
</script>

なお、上の例は次のように書かれていたかのように表示されます。

<u id="a1">A</u><br>
<i id="c2">C</i><br>
<br>
<br>

<span id="d01" style="color:red;">A<b>B</b></span><span>C</span><br>
<span id="d02" style="color:red;">A<b id="b1">B</b><i id="c1">C</i></span><br>
<span>A</span><span id="d03" style="color:red;"><b>B</b>C</span><br>
<span id="d04" style="color:red;"><u id="a2">A</u><b id="b2">B</b>C</span><br>

<span id="d05"><span><u id="x1">x</u>A<u id="n1">1</u></span><span><b id="x2">y</b>B<b id="n2">2</b></span><span><i id="x3">z</i>C<i id="n3">3</i></span></span><br>

また、上の例の jQuery の記述部分は jQuery を使用しなければ、次のように書き換えることもできます。

var b = document.createElement("b");
b.textContent = "B";
d01.appendChild(b);                             // A の後ろに B
var list = [b1, c1];
for (let i in list) {
  d02.appendChild(list[i]);                     // A の後ろに B、C
}
b = document.createElement("b");
b.textContent = "B";
d03.insertBefore(b, d03.firstChild);            // C の前に B
list = [a2, b2].reverse();
for (let i in list) {
  d04.insertBefore(list[i], d04.firstChild);    // C の前に A、B
}

var e = [].slice.call(document.querySelectorAll("#d05 span"));
e.forEach(function(e, i){
        let x = document.querySelector("#n" + (i+1));
        e.appendChild(x); });                   // A、B、C それぞれの後ろに 1 2 3
e.forEach(function(e, i){
        let x = document.getElementById("x" + (i+1));
        e.insertBefore(x, e.firstChild); });    // A、B、C それぞれの前に x y z
実行例(jQuery 使用)
実行例(jQuery 未使用)

○ appendTo、prependTo

指定した要素の、最後あるいは最初の子要素として挿入します。

append、prepend は引数として指定された要素を挿入するのに対して、appendTo、prependTo は 引数として指定した要素に挿入します。

記述例

挿入する要素として DOM 要素を指定すると、ドキュメント上にあったそれらは、コピーされて挿入されるのではなく、移動することになります(二番目と四番目の例)。ただし、挿入先が複数ある場合には2つ目以降はコピーされるようです。

したがって、挿入する要素に id が設定されている場合、同じ id を持つ要素が複数存在することになるので注意が必要です。

<u id="x1">x</u><br>
<u id="x2">x</u><br>

<div id="d01"><span style="color:red;">A</span><span style="color:blue;">B</span></div>
<!-- 以下略 -->

<script>
$("<b>x</b>").appendTo($("#d01 span"));    // 各 span 要素の最後の子要素として <b>x</b>
$("#x1").appendTo($("#d02 span"));         // 各 span 要素の最後の子要素として id="x1" の要素
$("<b>x</b>").prependTo($("#d03 span"));   // 各 span 要素の最初の子要素として <b>x</b>
$("#x2").prependTo($("#d04 span"));        // 各 span 要素の最初の子要素として id="x2" の要素
</script>

なお、上の例は次のように書かれていたかのように表示されます。

<br>
<br>

<div id="d01"><span style="color:red;">A<b>x</b></span><span style="color:blue;">B<b>x</b></span></div>
<div id="d02"><span style="color:red;">A<u id="x1">x</u></span><span style="color:blue;">B<u id="x1">x</u></span></div>
<div id="d03"><span style="color:red;"><b>x</b>A</span><span style="color:blue;"><b>x</b>B</span></div>
<div id="d04"><span style="color:red;"><u id="x2">x</u>A</span><span style="color:blue;"><u id="x2">x</u>B</span></div>

また、上の例の jQuery の記述部分は jQuery を使用しなければ、次のように書き換えることもできます。

なお、[].slice.call は Array.prototype.slice.call と書くこともでき、querySelectorAll などの戻り値を Array オブジェクトに変換します。

var x = document.createElement("b");
x.textContent = "x";
var e = [].slice.call(document.querySelectorAll("#d01 span"));
e.forEach(function(e){ e.appendChild(x); x=x.cloneNode(true); });    // 各 span 要素の最後の子要素として <b>x</b>
x = document.querySelector("#x1");
e = [].slice.call(document.querySelectorAll("#d02 span"));
e.forEach(function(e){ e.appendChild(x); x=x.cloneNode(true); });    // 各 span 要素の最後の子要素として id="x1" の要素
x = document.createElement("b");
x.textContent = "x";
e = [].slice.call(document.querySelectorAll("#d03 span"));
e.forEach(function(e){ e.insertBefore(x, e.firstChild); x=x.cloneNode(true); }); // 各 span 要素の最初の子要素として <b>x</b>
x = document.querySelector("#x2");
e = [].slice.call(document.querySelectorAll("#d04 span"));
e.forEach(function(e){ e.insertBefore(x, e.firstChild); x=x.cloneNode(true); }); // 各 span 要素の最初の子要素として id="x2" の要素
実行例(jQuery 使用)
実行例(jQuery 未使用)

○ wrapInner

対象要素の子要素を、指定した要素で囲むように挿入します。

記述例

挿入する要素として DOM 要素を指定しても append や prepend とは異なり、移動ではなくコピーされるようです。

ただし、挿入する要素に id が設定されている場合、同じ id を持つ要素が複数存在することになるので、やはり注意が必要です。

<u id="x1">1</u><u id="x2">2</u><br>

<div id="d01"><span style="color:red;">A</span><span style="color:blue;"><i>B</i></span></div>
<!-- 以下略 -->

<script>
$("#d01 span").wrapInner("<u>");                   // <u> ~ </u> で囲む
$("#d02 span").wrapInner("<u><b>x</b></u>");       // <u><b>x ~ </b></u> で囲む
$("#d03 span").wrapInner($("#x1"));                // <u id="x1">1 ~ </u> で囲む
$("#d04 span").wrapInner(function(i){ return "#x" + (i+1); }); // <u id="x1">1 ~ </u>、<u id="x2">2 ~ </u> で囲む
</script>

なお、上の例は次のように書かれていたかのように表示されます。

<u id="x1">1</u><u id="x2">2</u><br>

<div id="d01"><span style="color:red;"><u>A</u></span><span style="color:blue;"><u><i>B</i></u></span></div>
<div id="d02"><span style="color:red;"><u><b>xA</b></u></span><span style="color:blue;"><u><b>x<i>B</i></b></u></span></div>
<div id="d03"><span style="color:red;"><u id="x1">1A</u></span><span style="color:blue;"><u id="x1"><i>1B</i></u></span></div>
<div id="d04"><span style="color:red;"><u id="x1">1A</u></span><span style="color:blue;"><u id="x2"><i>2B</i></u></span></div>

また、上の例の jQuery の記述部分は jQuery を使用しなければ、次のように書き換えることもできます。

なお、[].slice.call は Array.prototype.slice.call と書くこともでき、querySelectorAll などの戻り値を Array オブジェクトに変換します。

var e = [].slice.call(document.querySelectorAll("#d01 span"));
e.forEach(function(e){ e.innerHTML = "<u>" + e.innerHTML + "</u>"; });         // <u> ~ </u> で囲む
e = [].slice.call(document.querySelectorAll("#d02 span"));
e.forEach(function(e){ e.innerHTML = "<u><b>x" + e.innerHTML + "</b></u>"; }); // <u><b>x~</b></u>で囲む
e = [].slice.call(document.querySelectorAll("#d03 span"));
var x = document.querySelector("#x1");
e.forEach(function(e){ 
        let outer = x.outerHTML;
        let splitPoint = outer.lastIndexOf("<");
        let former = outer.substring(0, splitPoint);
        let latter = outer.substring(splitPoint);
        e.innerHTML = former + e.innerHTML + latter; });                // <u id="x1">1 ~ </u> で囲む
e = [].slice.call(document.querySelectorAll("#d04 span"));
e.forEach(function(e, i){ 
        let x = document.querySelector("#x" + (i + 1));
        let outer = x.outerHTML;
        let splitPoint = outer.lastIndexOf("<");
        let former = outer.substring(0, splitPoint);
        let latter = outer.substring(splitPoint);
        e.innerHTML = former + e.innerHTML + latter; });  // <u id="x1">1~</u>、<u id="x2">2~</u> で囲む
実行例(jQuery 使用)
実行例(jQuery 未使用)

(3)親要素の挿入

親要素を挿入します。

メソッド引数機能戻り値
wrap(要素)要素:HTML文字列、DOM要素、jQuery オブジェクト(注)指定の要素で対象要素の一つひとつを囲む(指定の要素を対象要素の親にする)。jQuery オブジェクト
wrap(関数)jQuery オブジェクトを返す関数
関数の形式
function(index)
 index:   要素番号(0~)
戻り値:  変更したい HTML
関数が返した要素で対象要素の一つひとつを囲む(関数が返した要素を対象要素の親にする)。jQuery オブジェクト
wrapAll(要素)要素:HTML文字列、DOM要素、jQuery オブジェクト(注)対象要素全体をグループ化(一纏まりに)して、指定の要素で囲む(指定の要素を対象要素の親にする)。jQuery オブジェクト
wrapAll(関数)jQuery オブジェクトを返す関数
関数の形式
function()
戻り値:  変更したい HTML
対象要素全体をグループ化(一纏まりに)して、関数が返した要素で囲む(関数が返した要素を対象要素の親にする)。jQuery オブジェクト
注)セレクタ、DOM要素などに関しては、13.1.3 jQuery オブジェクトの生成 参照

記述例

wrap で、囲む(親になる)要素に id が設定されている場合、同じ id を持つ要素が複数存在することになるので、注意が必要です(二番目の例)。

wrapAll では、グループ化(一纏まりに)するために、要素の順番が変わることがありますので注意してください(四番目~六番目の例)。

<u id="x1">#</u><u id="x2">&</u><br>

<div id="d01"><span style="color:red;">A</span><span>x</span><span style="color:blue;"><i>B</i></span></div>
<!-- 以下略 -->

<script>
$("#d01 span[style]").wrap("<u><b>#</b></u>");                    // <u><b>x ~ </b></u> で囲む
$("#d02 span[style]").wrap($("#x1"));                             // <u id="x1"># ~ </u> で囲む
$("#d03 span[style]").wrap(function(i){ return "#x" + (i+1); });  // <u id="x1"># ~ </u>、<u id="x2">& ~ </u> で囲む
$("#d11 span[style]").wrapAll("<u><b>#</b></u>");                 // <u><b>x ~ </b></u> で囲む
$("#d12 span[style]").wrapAll($("#x1"));                          // <u id="x1"># ~ </u> で囲む
$("#d13 span[style]").wrapAll(function(){ return "#x2"; });       // <u id="x2">& ~ </u> で囲む
</script>

なお、上の例は次のように書かれていたかのように表示されます。

<u id="x1">#</u><u id="x2">&</u><br>

<div id="d01"><u><b>#<span style="color:red;">A</span></b></u><span>x</span><u><b>#<span style="color:blue;"><i>B</i></span></b></u></div>
<div id="d02"><u id="x1">#<span style="color:red;">A</span></u><span>x</span><u id="x1">#<span style="color:blue;"><i>B</i></span></u></div>
<div id="d03"><u id="x1">#<span style="color:red;">A</span></u><span>x</span><u id="x2">&<span style="color:blue;"><i>B</i></span></u></div>
<div id="d04"><u><b>#<span style="color:red;">A</span><span style="color:blue;"><i>B</i></span></b></u><span>x</span></div>
<div id="d05"><u id="x1">#<span style="color:red;">A</span><span style="color:blue;"><i>B</i></span></u><span>x</span></div>
<div id="d06"><u id="x2">&<span style="color:red;">A</span><span style="color:blue;"><i>B</i></span></u><span>x</span></div>

また、上の例の jQuery の記述部分は jQuery を使用しなければ、次のように書き換えることもできます。

なお、[].slice.call は Array.prototype.slice.call と書くこともでき、querySelectorAll などの戻り値を Array オブジェクトに変換します。

var e = [].slice.call(document.querySelectorAll("#d01 span"));
e.forEach(function(e) { wrap(e, appendChild1); });                 // <u><b>x ~ </b></u> で囲む
e = [].slice.call(document.querySelectorAll("#d02 span"));
e.forEach(function(e) { wrap(e, appendChild2, "x1"); });           // <u id="x1"># ~ </u> で囲む
e = [].slice.call(document.querySelectorAll("#d03 span"));
e.forEach(function(e, i) { wrap(e, appendChild2, "x" + (i+1)); }); // <u id="x1"># ~ </u>、<u id="x2">& ~ </u> で囲む
e = [].slice.call(document.querySelectorAll("#d11 span"));
wrapAll(e, appendChild1);                                          // <u><b>x ~ </b></u> で囲む
e = [].slice.call(document.querySelectorAll("#d12 span"));
wrapAll(e, appendChild2, "x1");                                    // <u id="x1"># ~ </u> で囲む
e = [].slice.call(document.querySelectorAll("#d13 span"));
wrapAll(e, appendChild2, "x2");                                    // <u id="x2">& ~ </u> で囲む

function wrap(e, append, param) {
  let parent = e.parentNode;
  let next = e.nextSibling;
  parent.insertBefore(append(e, param), next);
}
function wrapAll(e, append, param) {
  let parent = e[0].parentNode;
  let wrap = append(e, param);
  let next = parent.firstChild;
  parent.insertBefore(wrap, next);
}

function appendChild1(e) {
  let u = document.createElement("u");
  let b = document.createElement("b");
  b.textContent = "#";
  appendChild(b, e);
  u.appendChild(b);
  return u;
}

function appendChild2(e, id) {
  let wrap = document.querySelector("#" + id);
  let w = wrap.cloneNode(true);
  let farthest = getFarthestDescendant(w);
  appendChild(farthest, e);
  return w;
}

function appendChild(parent, child) {
  if (child instanceof Array) {
    for (let i in child) {
      parent.appendChild(child[i]);
    }
  }
  else {
    parent.appendChild(child);
  }
}

function getFarthestDescendant(child) {
  while (child.firstElementChild != null) 
    child = child.firstElementChild;
  return child;
}
実行例(jQuery 使用)
実行例(jQuery 未使用)

また、囲む(親になる)要素として同じ階層レベルの要素が複数書かれていた場合は、先に記述されていた方で分割され、その間に囲むことになるようです。

下の例だと、<u> と <b> は兄弟要素なので、階層レベルは同じですが、先に記述してある <u> で分割されます。そして、"<span><u>#" と "</u><b>&</b></span>" とで囲むことになります。

記述例
<div id="d01"><span style="color:red;">A</span> <span style="color:blue;"><i>B</i></span></div>

<script>
$("#d01 span[style]").wrap("<span><u>#</u><b>&</b></span>");
</script>

上の例は次のように書かれていたかのように表示されます。

<div id="d01"><span><u>#<span style="color:red;">A</span></u><b>&</b></span> <span><u>#<span style="color:blue;"><i>B</i></span></u><b>&</b></span></div>
実行例(jQuery 使用)

(4)要素の削除

要素を削除します。

メソッド引数機能戻り値
remove([選択条件])選択条件:セレクタ(注)対象要素とその子孫要素を削除する。ただし、選択条件が指定されている場合はそれに一致する対象要素を削除する。jQuery オブジェクト
empty()なし対象要素内の子孫要素をテキストも含めてすべて削除する。jQuery オブジェクト
detach([選択条件])選択条件:セレクタ(注)対象要素とその子孫要素をデータ(イベントなど)を残したまま削除する。ただし、選択条件が指定されている場合はそれに一致する対象要素を削除する。jQuery オブジェクト
unwrap()なし対象要素の親要素を削除する。jQuery オブジェクト
注)セレクタに関しては、13.1.3 jQuery オブジェクトの生成 参照

記述例

remove は、削除する要素やその子孫の属性やテキストなどは戻り値として返しますが、削除された要素に関連付けられたイベントなどのデータは戻り値にはありません。したがって、戻り値内の要素をドキュメントに挿入してもイベントは発生しません(一番目の例)。ただし、戻り値に残らないのは jQuery の情報です。onmouseenter などで指定したイベントハンドラは残りますので、ドキュメントに挿入したら元のようにイベントは発生します。

detach では、イベントなどのデータも残すところが remove とは異なります(三番目の例)。ただし、メモリ上に残ることになりますので注意してください。

empty は、子孫のみを削除し対象要素自体は削除しません。そのため、他のメソッドとは異なり対象要素の領域は残り、Cc は元の場所にとどまります(四番目の例)。

<style>
span {
  display:inline-block;
  width:2em;
}
</style>

<div id="d01"><span style="color:red;"><b>A</b>a</span><span style="color:blue;"><i>B</i>b</span><span style="color:green;"><u>C</u>c</span></div>
<!-- 以下略 -->

<script>
$("#d01 span:eq(1)").hover(
  function() { $(this).css("background-color", "yellow"); },
  function() { $(this).css("background-color", "transparent"); }
);  
$("#d11 span:eq(1)").hover(
  function() { $(this).css("background-color", "yellow"); },
  function() { $(this).css("background-color", "transparent"); }
);  
var a = $("#d01 span:eq(1)").remove();         // B とその子孫を削除(jQueryデータは保持しない)
$("#d01").append(a);                             // 削除した要素を挿入
$("#d02 span").remove(":eq(1)");               // B とその子孫を削除
a = $("#d11 span:eq(1)").detach();             // B とその子孫を削除(jQueryデータは保持する)
$("#d11").append(a);                             // 削除した要素を挿入
$("#d21 span:eq(1)").empty();                  // B の子孫を削除(jQueryデータは保持しない)
$("#d31 i").unwrap();                          // 親要素の <span style="color:blue;"> を削除
</script>

上の例は次のように書かれていたかのように表示されます。

<div id="d01"><span style="color:red;"><b>A</b>a</span><span style="color:green;"><u>C</u>c</span><span style="color:blue;"><i>B</i>b</span></div>
<div id="d02"><span style="color:red;"><b>A</b>a</span><span style="color:green;"><u>C</u>c</span></div>
<div id="d11"><span style="color:red;"><b>A</b>a</span><span style="color:green;"><u>C</u>c</span><span style="color:blue;"><i>B</i>b</span></div>
<div id="d21"><span style="color:red;"><b>A</b>a</span><span style="color:blue;"></span><span style="color:green;"><u>C</u>c</span></div>
<div id="d01"><span style="color:red;"><b>A</b>a</span><i>B</i>b<span style="color:green;"><u>C</u>c</span></div>

また、上の例の jQuery の記述部分は jQuery を使用しなければ、次のように書き換えることもできます。

ただし、remove も detach も 区別なく作成していますので、イベントハンドラは削除されません(1番目の例でもイベントが発生します)。

var e = document.querySelector("#d01 span:nth-of-type(2)");
e.addEventListener("mouseenter", function() {this.style.backgroundColor = "yellow";}, false);
e.addEventListener("mouseleave", function() {this.style.backgroundColor = "transparent";}, false);
var parent = e.parentNode;
var a = remove(e);                                 // B とその子孫を削除
parent.appendChild(a);                               // 削除した要素を挿入
e = document.querySelectorAll("#d02 span");
a = remove(e[1]);                                  // B とその子孫を削除
e = document.querySelector("#d11 span:nth-of-type(2)");
e.addEventListener("mouseenter", function() {this.style.backgroundColor = "yellow";}, false);
e.addEventListener("mouseleave", function() {this.style.backgroundColor = "transparent";}, false);
parent = e.parentNode;
a = remove(e);                                     // B とその子孫を削除
parent.appendChild(a);                               // 削除した要素を挿入
e = document.querySelector("#d21 span:nth-of-type(2)");
empty(e);                               // B の子孫を削除
e = document.querySelector("#d31 i");
unwrap(e);                              // 親要素の <span style="color:blue;"> を削除

function remove(e) {
  let parent = e.parentNode;
  return parent.removeChild(e);
}
function empty(e) {
  e.innerHTML = "";
  return e;
}

function unwrap(e) {
  let parent = e.parentNode;
  let grandParent = parent.parentNode;
  let children = parent.childNodes;
  while (children.length > 0) {
    grandParent.insertBefore(children[0], parent);      // 挿入のたびに children の内容が変わる
  }
  grandParent.removeChild(parent);
}

一番目の例の Bb はイベントが発生しませんが、三番目の例の Bb はイベントが発生しますので、マウスを重ねると背景色が黄色くなります。

ただし、jQuery 未使用の方は両方の例ともイベントが発生し、マウスを重ねると背景色が黄色くなります。

実行例(jQuery 使用)
実行例(jQuery 未使用)

(5)要素の置換

要素を置換します。

メソッド引数機能戻り値
replaceAll(置換対象)置換対象:セレクタ(注)置換対象を対象要素で置換する。jQuery オブジェクト
replaceWith(置換要素)要素:HTML文字列、DOM要素、jQuery オブジェクト(注)指定の置換要素で対象要素を置換する。jQuery オブジェクト
replaceWith(関数)jQuery オブジェクトを返す関数
関数の形式
function(index[, html])
 index:   要素番号(0~)
 html:    変更前の HTML
戻り値:  変更したい HTML
関数が返した要素で対象要素を置換する。jQuery オブジェクト
注)セレクタ、DOM要素に関しては、13.1.3 jQuery オブジェクトの生成 参照

記述例

置換する要素(置き換える側)として DOM 要素を指定すると、ドキュメント上にあったそれらは、コピーされて置換されるのではなく、移動することになります(二番目と四番目の例)。ただし、置換先が複数ある場合には2つ目以降はコピーされるようです。

したがって、置換する要素に id が設定されている場合、同じ id を持つ要素が複数存在することになるので注意が必要です。

<div id="d01"><span>A</span><span>B</span><span>C</span><span>D</span><span>E</span></div>
<!-- 以下略 -->

<script>
$("<span style='color:red;'>(X)</span>").replaceAll("#d01 span:gt(2)");         // 四番目以降を (X) で置換
$("#d02 span:eq(1)").replaceAll("#d02 span:gt(2)");            // 四番目以降を二番目で置換(二番目が移動)
$("#d11 span:gt(2)").replaceWith("<span style='color:red;'>(X)</span>");        // (X) で四番目以降を置換
$("#d12 span:gt(2)").replaceWith($("#d12 span:eq(1)"));        // 二番目で四番目以降を置換(二番目が移動)
$("#d13 span:gt(2)").replaceWith(
            function(i, e){ return "<span style='color:red;'>" + e + "</span>" });  // 関数の戻り値で四番目以降を置換
</script>

上の例は次のように書かれていたかのように表示されます。

<div id="d01"><span>A</span><span>B</span><span>C</span><span style="color:red;">(X)</span><span style="color:red;">(X)</span></div>
<div id="d02"><span>A</span><span>C</span><span>B</span><span>B</span></div>
<div id="d11"><span>A</span><span>B</span><span>C</span><span style="color:red;">(X)</span><span style="color:red;">(X)</span></div>
<div id="d12"><span>A</span><span>C</span><span>B</span><span>B</span></div>
<div id="d13"><span>A</span><span>B</span><span>C</span><span style="color:red;">D</span><span style="color:red;">E</span></div>

また、上の例の jQuery の記述部分は jQuery を使用しなければ、次のように書き換えることもできます。

なお、[].slice.call は Array.prototype.slice.call と書くこともでき、querySelectorAll などの戻り値を Array オブジェクトに変換します。

var e = [].slice.call(document.querySelectorAll("#d01 span"));
replace(e, 2, getSource1);            // 四番目以降を (X) で置換
var param = document.querySelector("#d02 span:nth-child(2)");
e = [].slice.call(document.querySelectorAll("#d02 span"));
replace(e, 2, getSource2);            // 四番目以降を二番目で置換(二番目が移動)
e = [].slice.call(document.querySelectorAll("#d11 span"));
replace(e, 2, getSource1);            // (X) で四番目以降を置換
param = document.querySelector("#d12 span:nth-child(2)");
e = [].slice.call(document.querySelectorAll("#d12 span"));
replace(e, 2, getSource2);            // 二番目で四番目以降を置換(二番目が移動)
e = [].slice.call(document.querySelectorAll("#d13 span"));
replace(e, 2, getSource3);            // 関数の戻り値で四番目以降を置換


function getSource1() {
  return getSource("(X)");
}
function getSource2() {
  let temp = param;
  param = param.cloneNode(true);
  return temp;
}
function getSource3(e) {
  return getSource(e.textContent);
}
function getSource(text) {
  let span = document.createElement("span");
  span.style.color = "red";
  span.textContent = text;
  return span;
}

function replace(target, n, getSource) {
  if (target instanceof Array) {
      let parent = target[0].parentNode;
      target.forEach(function(e, i) {
                   if (i > n) {
                     parent.replaceChild(getSource(e), e);
                   }
                 });
  }
  else {
    target.parentNode.replaceChild(getSource(), target);
  }
}
実行例(jQuery 使用)
実行例(jQuery 未使用)

(6)要素の内容

要素を置換します。

メソッド引数機能戻り値
html()なし対象要素の内容を表す HTML 文字列(innerHTML)を取得する。ただし、対象要素が複数ある場合は最初の要素が対象になる。文字列
html(HTML)HTML:HTML文字列指定された HTML を対象要素に設定する。jQuery オブジェクト
html(関数)jQuery オブジェクトを返す関数
関数の形式
function(index[, html])
 index:   要素番号(0~)
 html:    変更前の HTML
戻り値:  変更したい HTML
関数が返した HTML文字列を対象要素に設定する。jQuery オブジェクト
text()なし対象要素のテキストを取得する。対象要素が複数ある場合もすべてを取得する。文字列
text(テキスト)テキスト:文字列指定されたテキストを対象要素に設定する。jQuery オブジェクト
text(関数)jQuery オブジェクトを返す関数
関数の形式
function(index[, text])
 index:   要素番号(0~)
 text:    変更前のテキスト
戻り値:  変更したいテキスト
関数が返した文字列を対象要素に設定する。jQuery オブジェクト

対象となる要素が複数あった場合、html はその中の最初の要素の HTML を返しますが、text はすべての要素のテキストを返します(二番目と五番目の例)。

また、text は設定する文字列の中にタグが書かれていてもそのまま文字列として設定されます。

<div id="d01"><span>A</span><span>B</span><span>C</span><span>D</span><span>E</span></div>
<div id="d02"><span>A</span><span style="color:blue;"><i>B</i></span><span>C</span><span style="color:red;">D</span><span>E</span></div>
<div id="d03"><span>A</span><span>B</span><span>C</span><span style="color:red;">D</span><span>E</span></div>
<div id="d11"><span>A</span><span>B</span><span>C</span><span style="color:red;">D</span><span style="color:red;">E</span></div>
<div id="d12"><span>A</span><span style="color:blue;">B</span><span>C</span><span style="color:red;">D</span><span>E</span></div>
<div id="d13"><span>A</span><span>B</span><span>C</span><span style="color:red;">D</span><span>E</span></div>

<script>
$("#d01 span:gt(2)").html("<span style='color:red;'>X</span>");      // 四番目以降を置換
var a = $("#d02 span:gt(0)").html();                                 // 二番目の内容を HTML 文字列で返す
$("#d02 span:eq(3)").html("<u>" + a + "</u>");                       // 四番目に設定
$("#d03 span:eq(3)").html(function(i, html) { return "<u>" + html + "</u>" }); // 四番目に設定
$("#d11 span:gt(2)").text("X");                                      // 四番目以降を置換
a = $("#d12 span:gt(0)").text();                                     // 二番目以降のテキストすべてを返す
$("#d12 span:eq(3)").text(a);                                        // 四番目に設定
$("#d13 span:eq(3)").text(function(i, text) { return "(" + text + ")" });  // 四番目に設定

上の例は次のように書かれていたかのように表示されます。

<div id="d01"><span>A</span><span>B</span><span>C</span><span><span style="color:red;">X</span></span><span><span style="color:red;">X</span></span></div>
<div id="d02"><span>A</span><span style="color:blue;"><i>B</i></span><span>C</span><span style="color:red;"><u><i>B</i></u></span><span>E</span></div>
<div id="d03"><span>A</span><span>B</span><span>C</span><span style="color:red;"><u>D</u></span><span>E</span></div>
<div id="d11"><span>A</span><span>B</span><span>C</span><span style="color:red;">X</span><span style="color:red;">X</span></div>
<div id="d12"><span>A</span><span style="color:blue;">B</span><span>C</span><span style="color:red;">BCDE</span><span>E</span></div>
<div id="d13"><span>A</span><span>B</span><span>C</span><span style="color:red;">(D)</span><span>E</span></div>

また、上の例の jQuery の記述部分は jQuery を使用しなければ、次のように書き換えることもできます。

なお、[].slice.call は Array.prototype.slice.call と書くこともでき、querySelectorAll などの戻り値を Array オブジェクトに変換します。

var e = [].slice.call(document.querySelectorAll("#d01 span"));
e.forEach(function(e, i) { if (i > 2) e.innerHTML = "<span style='color:red;'>X</span>"; }); // 四番目以降を置換
e = [].slice.call(document.querySelectorAll("#d02 span"));
var a = e[1].innerHTML;                                             // 二番目の内容を HTML 文字列で返す
document.querySelector("#d02 span:nth-of-type(4)").innerHTML = "<u>" + a + "</u>";     // 四番目に設定
e = [].slice.call(document.querySelectorAll("#d03 span:nth-of-type(4)"));
e.forEach(function(e, i) { e.innerHTML = "<u>" + e.innerHTML + "</u>"; });  // 四番目に設定
e = [].slice.call(document.querySelectorAll("#d11 span"));
e.forEach(function(e, i) { if (i > 2) e.textContent = "X"; });              // 四番目以降を置換
e = [].slice.call(document.querySelectorAll("#d12 span"));
a = "";
e.forEach(function(e, i) { if (i > 0) a += e.textContent; });               // 二番目以降のテキストを返す
document.querySelector("#d12 span:nth-of-type(4)").innerText = a;            // 四番目以降を置換
e = [].slice.call(document.querySelectorAll("#d13 span:nth-of-type(4)"));
e.forEach(function(e, i) { e.textContent = "(" + e.textContent + ")"; });   // 四番目に設定
実行例(jQuery 使用)
実行例(jQuery 未使用)

(7)要素のコピー

要素を置換します。

メソッド引数機能戻り値
clone([イベント[,ディープ]])イベント:イベントハンドラもコピーする(true)(規定値:false)
ディープ:子孫のイベントハンドラもコピーする(true)(規定値:false)
引数に従って対象要素をコピーする。jQuery オブジェクト

記述例

一つ目の引数が false だと、対象要素の子孫要素の情報はコピーされますが、 data やイベントハンドラは全くコピーされません(一番目の例)。

一つ目の引数を true にすると、対象要素の data やイベントハンドラはコピーされますが、子孫要素のそれらはコピーされません(三番目の例)。

子孫要素の data やイベントハンドラもコピーするには、二つ目の引数を true にします(四番目の例)。

<div id="p" style="width:80px;background-color:lightyellow;padding:10px;">
  <div id="c" style="height:20px;background-color:lightgreen;">
    AAAAA
  </div>
</div>

<span id="d01"></span><span id="d02"></span><br>
<span id="d03"></span><span id="d04"></span><br>

<script>
$("#p").hover(
  function() { $(this).css("background-color", "yellow"); },
  function() { $(this).css("background-color", "lightyellow"); }
);  
$("#c").hover(
  function() { $(this).css("background-color", "green"); },
  function() { $(this).css("background-color", "lightgreen"); }
);  

$("#d01").append($("#p").clone(false,false));   // イベントはコピーしない
$("#d02").append($("#p").clone(false,true));    // イベントはコピーしない
$("#d03").append($("#p").clone(true,false));    // 対象要素のイベントをコピーする
$("#d04").append($("#p").clone(true,true));     // 対象要素とその子孫のイベントをコピーする
</script>

上の例は次のように書かれていたかのように表示されます。

<div id="p" style="width:80px;background-color:lightyellow;padding:10px;">
  <div id="c" style="height:20px;background-color:lightgreen;">
    AAAAA
  </div>
</div>

<span id="d01">
<div id="p" style="width:80px;background-color:lightyellow;padding:10px;">
  <div id="c" style="height:20px;background-color:lightgreen;">
    AAAAA
  </div>
</div>
</span><span id="d02">
<div id="p" style="width:80px;background-color:lightyellow;padding:10px;">
  <div id="c" style="height:20px;background-color:lightgreen;">
    AAAAA
  </div>
</div>
</span><br>
<span id="d03">
<div id="p" style="width:80px;background-color:lightyellow;padding:10px;" onmouseenter="this.style.backgroundColor='yellow';" onmouseleave="this.style.backgroundColor='lightyellow';">
  <div id="c" style="height:20px;background-color:lightgreen;">
    AAAAA
  </div>
</div>
</span><span id="d04">
<div id="p" style="width:80px;background-color:lightyellow;padding:10px;" onmouseenter="this.style.backgroundColor='yellow';" onmouseleave="this.style.backgroundColor='lightyellow';">
  <div id="c" style="height:20px;background-color:lightgreen;" onmouseenter="this.style.backgroundColor='green';" onmouseleave="this.style.backgroundColor='lightgreen';">
    AAAAA
  </div>
</div>
</span><br>

また、上の例の jQuery の記述部分は jQuery を使用しなければ、次のように書き換えることもできます。

ただし、jQuery では、data やイベントハンドラは jQuery 独自の機能で実現していますので、ここではそれに似せて実現しています。

addEvent(p, true);

d01.appendChild(clone(p, false, false));   // イベントはコピーしない
d02.appendChild(clone(p, false, true));    // イベントはコピーしない
d03.appendChild(clone(p, true, false));    // 対象要素のイベントをコピーする
d04.appendChild(clone(p, true, true));     // 対象要素とその子孫のイベントをコピーする

function addEvent(e, deep) {
  e.addEventListener("mouseenter", function() {this.style.backgroundColor = "yellow";}, false);
  e.addEventListener("mouseleave", function() {this.style.backgroundColor = "lightyellow";}, false);
  if (deep) {
    let children = e.childNodes;
    for(let i in children) {
      if (children[i].addEventListener != undefined) {
        children[i].addEventListener("mouseenter", function() {this.style.backgroundColor = "green";}, false);
        children[i].addEventListener("mouseleave", function() {this.style.backgroundColor = "lightgreen";}, false);
      }
    }
  }
}

function clone(src, event, deep) {
  let a = src.cloneNode(true);
  a.removeAttribute("id");      // id の重複を防ぐ
  if (event) {
    addEvent(a, deep);
  }
  return a;
}

一番下の左側は子要素のイベントが発生しませんが、右側は子要素のイベントが発生します。

実行例(jQuery 使用)
実行例(jQuery 未使用)

13.3.8  フォーム

フォームの情報、あるいは配列やオブジェクトをURLクエリ文字列に変換(シリアライズ)する処理

メソッド引数機能戻り値
serialize()なし対象フォーム要素の情報をURLクエリ文字列に変換する。文字列
serializeArray()なし対象フォーム要素の情報を配列に変換する。オブジェクトの配列
[ {name:"属性名", value:"値"}, ... ]
$.param(データ[, 旧型式])データ:配列またはオブジェクト
旧型式:v1.4以前の形式にする(true)(規定値:false)
指定した属性名の値を取得する。文字列
注)form 要素の子要素には name 属性が必要です。
注)file 選択の情報は出力されません。
注)チェックボックスの情報はチェックしていないと出力されません。

記述例

serializeArray の戻り値はオブジェクトの配列なのでそのまま表示したのではよく分かりません。そこで、以下の例では分かりやすくするために文字列として表示しています(二番目の例)。

$.param の第一引数を $("form").serializeArray() などのフォームデータにした場合は第二引数にかかわらず結果は旧形式になるようです(三番目、四番目の例)。それに対して、オブジェクトの配列を第一引数にした場合は、第二引数が有効になるようです(五番目、六番目の例)。

<form>
  <input type="text" name="a" value="TEXT">
  <input type="checkbox" name="b" value="1"><input type="checkbox" name="b" value="2" checked><input type="checkbox" name="b" value="3" checked>
</form>
<span id="d01"></span><br>
<!-- 以下略 -->

<script>
d01.textContent = $("form").serialize();   // URLクエリ文字列に変換
var s = {x:""};
var result = $("form").serializeArray();   // 結果はオブジェクトの配列
var delim = "";
result.forEach(disp, s);
d02.textContent = "[" + s["x"] + "]";       // 分かりにくいので文字列化
var obj = $("form").serializeArray();
d03.textContent = $.param(obj);
d04.textContent = $.param(obj, true);
obj = {a:'TEXT', b:[2,3]};
d05.textContent = decodeURIComponent($.param(obj));
d06.textContent = $.param(obj, true);

function disp(item) {
  this["x"] += delim + "{name:" + item.name + ",value=" + item.value + "}";
  delim = ",";
}
</script>

また、上の例の jQuery の記述部分は jQuery を使用しなければ、次のように書き換えることもできます。

d01.textContent = serialize(document.forms[0]);   // URLクエリ文字列に変換
var s = {x:""};
var result = serializeArray(document.forms[0]);   // 結果はオブジェクトの配列
var delim = "";
result.forEach(disp, s);
d02.textContent = "[" + s["x"] + "]";       // 分かりにくいので文字列化
d03.textContent = param(result);
d04.textContent = param(result, true);
var obj = {a:'TEXT', b:[2,3]};
d05.textContent = param(obj);
d06.textContent = param(obj, true);

function serialize(form) {
  let s = "";
  let d = "";
  let e = form.elements;
  for(let i = 0 ; i < e.length ; i++) {
    let eCol = e[i];
    if (eCol.type === "checkbox") {
      if (eCol.checked)
        s += d + eCol.name + "=" + eCol.value;
    }
    else {
      s += d + eCol.name + "=" + eCol.value;
    }
    d = "&";
  }
  return s;
}
function serializeArray(form) {
  let arr = new Array();
  let d = "";
  let e = form.elements;
  for(let i = 0 ; i < e.length ; i++) {
    let eCol = e[i];
    if (eCol.type === "checkbox") {
      if (eCol.checked)
        arr.push({"name": eCol.name, "value": eCol.value});
    }
    else {
      arr.push({"name": eCol.name, "value": eCol.value});
    }
  }
  return arr;
}
function param(obj, traditional) {
  let s = "";
  let d = "";
  if (obj instanceof Array) {
    for (let i in obj) {
      s += d + obj[i].name + "=" + obj[i].value;
      d = "&";
    }
  }
  else {
    for (let name in obj) {
      let value = obj[name];
      if (value instanceof Array) {
        let b = (traditional) ? "" : "[]";
        for (let i in value) {
          s += d + name + b + "=" + value[i];
          d = "&";
        }
      }
      else {
        s += d + name + "=" + value;
        d = "&";
      }
    }
  }
  return s;
}

function disp(item) {
  this["x"] += delim + "{name:" + item.name + ",value=" + item.value + "}";
  delim = ",";
}
実行例(jQuery 使用)
実行例(jQuery 未使用)

13.3.9  イベント

イベントハンドラの設定解除する処理を記述します。ただし、jQuery のイベントは javascript のイベントとは違う独自の機能として実装されています。

イベントは、イベントが発生した要素からその先祖要素に順番にイベントが発生していきます。順番にイベントが発生することを「イベントの伝播」といいます。詳しくは「10.2 イベントの伝播」を参照してください。

イベントの伝播する方向として、子孫方向(Capture フェーズ)と先祖方向(Bubbling フェーズ)がありますが、jQuery は、先祖方向(Bubbling フェーズ)です。

また、このイベントの伝播は、イベントハンドラで false を返すことで終わらせることができます。このとき、preventDefault が呼び出され、イベントハンドラは実行されずその要素の本来の機能が実行されます。そして、stopPropagation が呼び出されイベントの伝播が終了させられます。

(1)設定

イベント発生時に実行する処理(イベントハンドラ)の設定や削除、あるいはイベントの発生を行います。

(1-1)イベントハンドラの設定(on、one)

イベントハンドラの設定を行います。ただし、設定されるイベントは、on の場合は何回でも発生しますが、one の場合は1回限りです。

また、対象要素はイベントを設定するときには存在している必要があります。それに対して「イベント要素」を指定した場合はイベント発生時に存在していればイベントハンドラが起動します。

メソッド引数機能戻り値
on(イベント[,イベント要素][,引数],イベントハンドラ)イベント:イベント名(注1)
イベント要素:セレクタ(注2)
引数:イベントハンドラへの引数
イベントハンドラ:関数(注3)
対象要素内のイベント要素にイベントを設定するjQuery オブジェクト
on(イベントマップ[,イベント要素][,引数])イベントマップ:イベント名とイベントハンドラのマップ
イベント要素:セレクタ
引数:イベントハンドラへの引数
対象要素に複数のイベントとイベントハンドラを設定するjQuery オブジェクト
one(イベント[,イベント要素][,引数],イベントハンドラ)イベント:イベント名(注1)
イベント要素:セレクタ(注2)
引数:イベントハンドラへの引数
イベントハンドラ:関数(注3)
対象要素内のイベント要素に、一度だけ実行される、イベントを設定するjQuery オブジェクト
one(イベントマップ[,イベント要素][,引数])イベントマップ:イベント名とイベントハンドラのマップ
イベント要素:セレクタ
引数:イベントハンドラへの引数
対象要素に、一度だけ実行される、複数のイベントとイベントハンドラを設定するjQuery オブジェクト
注1)空白区切りで複数設定でき、名前空間も指定できる。名前空間に関しては、(1-2)イベントハンドラの削除(off) 参照
注2)セレクタに関しては、13.1.3 jQuery オブジェクトの生成 参照
注3)false を指定すると false を返す関数が記述されたと見なされる。また、関数が false を返すとイベントの伝播が終了する

一番目の例は、"×××"、"○○○"ともイベント設定時には存在していません。そのため、イベントハンドラが設定されず(親要素にも設定されず) "×××"の方はイベントが発生しません。それに対して、"○○○"の方はその親要素である d02 にイベントが設定されているのでイベントが発生し、その span 子要素に対し処理が行われ "○○○" と表示されます。

二番目の例は、右側のイベントハンドラが false を返しているのに対して左側は返していません。イベントハンドラが false を返すとイベントの伝播が止まります。したがって、 false を返した右側は親要素である d11 のイベントハンドラが実行されませんが、左側は d11 のイベントハンドラが実行され "parent" が表示されます。

三番目の例は、イベントハンドラに引数を渡しています。

記述例
<div id="disp" style="background-color:yellow;width:3em;height:1.5em;"> </div>
<span id="d01"></span><span id="d02"></span><br>
<span id="d11"><span>child</span> <span>child</span></span><br>
<span id="d21"><span>one</span> <span>two</span><span>three</span></span><br>
<div id="d31">MOUSE</div>

<script>
$("#d01 span").on("mousemove",function(){disp.textContent=this.textContent;});   // イベントを子要素に設定
$("#d02").on("mousemove", "span", function(){disp.textContent=this.textContent;}); // イベントを親要素に設定
$("#d11").on("mousemove", function(){disp.textContent="parent";});
$("#d11").on("mousemove", "span:eq(0)", function(){disp.textContent=this.textContent;}); // 親要素も実行される
$("#d11").on("mousemove", "span:eq(1)", function(){disp.textContent=this.textContent;return false;}); // 伝播を止める
$("#d21 span:eq('0')").on("mousemove", {kanji:"壱",yomi:"いち"}, content);
$("#d21 span:eq('1')").on("mousemove", {kanji:"弐",yomi:"に"}, content);
$("#d21 span:eq('2')").on("mousemove", {kanji:"参",yomi:"さん"}, content);
$("#d31").on(
{
  mouseenter: function(){disp.textContent="mouseenter";},
  mouseleave: function(){disp.textContent="mouseleave";},
  click: function(){disp.textContent="click";},
  dblclick: function(){disp.textContent="dblclick";},
  contextmenu: function(){disp.textContent="contextmenu";}
});
appendChild(d01, "×××");       // 要素を追加
appendChild(d02, "○○○");
$("span").on("mouseleave", function(){disp.textContent="";});

function appendChild(e, content) {
  let d = document.createElement("span");
  d.textContent = content;
  e.appendChild(d);
}
function content(event){
  disp.innerHTML="<ruby>" + event.data.kanji + "<rt>" + event.data.yomi + "</rt></ruby>";
}
</script>

また、上の例の jQuery の記述部分は jQuery を使用しなければ、次のように書き換えることもできます。

なお、[].slice.call は Array.prototype.slice.call と書くこともでき、querySelectorAll などの戻り値を Array オブジェクトに変換します。

var e = [].slice.call(document.querySelectorAll("#d01 span"));       // イベントを子要素に設定
e.forEach(function(e) { e.addEventListener("mousemove",function(){disp.textContent=this.textContent;});});
d02.addEventListener("mousemove",                                    // イベントを親要素に設定
    function(){
      let children = [].slice.call(d02.querySelectorAll("span"));
      for (let i in children) {
        disp.textContent=children[i].textContent;   // span 子要素を処理
      }
    });
d11.addEventListener("mousemove",function(){ disp.textContent="parent"; },false);   // Bubbling フェーズ
d11.querySelector("span:nth-of-type(1)").addEventListener("mousemove",exec1,false);  // 親要素も実行される
d11.querySelector("span:nth-of-type(2)").addEventListener("mousemove",exec2,false);  // 親要素は実行されない
d21.querySelector("span:nth-of-type(1)").addEventListener("mousemove",content({kanji:"壱",yomi:"いち"}));
d21.querySelector("span:nth-of-type(2)").addEventListener("mousemove",content({kanji:"弐",yomi:"に"}));
d21.querySelector("span:nth-of-type(3)").addEventListener("mousemove",content({kanji:"参",yomi:"さん"}));
setEvents(d31,
    {
      mouseenter: function(){disp.textContent="mouseenter";},
      mouseleave: function(){disp.textContent="mouseleave";},
      click: function(){disp.textContent="click";},
      dblclick: function(){disp.textContent="dblclick";},
      contextmenu: function(){disp.textContent="contextmenu";}
    }
);
appendChild(d01, "×××");
appendChild(d02, "○○○");
e = [].slice.call(document.querySelectorAll("span"));
e.forEach(function(e) { e.addEventListener("mouseleave", function(){disp.textContent="";}); });

function exec1(event){
  disp.textContent=this.textContent;
}
function exec2(event){
  disp.textContent=this.textContent;
  event.stopPropagation();         // イベントの伝播を止める
}
function appendChild(e, content) {
  let d = document.createElement("span");
  d.textContent = content;
  e.appendChild(d);
}
function content(map){
  return function(){
    disp.innerHTML="<ruby>" + map.kanji + "<rt>" + map.yomi + "</rt></ruby>";
  }
}
function setEvents(e, map) {
  for(let key in map) {
    e.addEventListener(key, map[key]);
  }
}

文字列にマウスを重ねてください(最後の文字列はマウスを重ねたり、ダブルクリックしたりいろいろしてください。黄色い背景色のところにイベントハンドラが文字列を設定します。

実行例(jQuery 使用)
実行例(jQuery 未使用)

on はイベントを何回でも発生させますが、one は1回限りです。

記述例
<div id="disp" style="background-color:yellow;width:12em;"> </div>
<span id="d01">=== on ===</span> <span id="d02">=== one ===</span><br>

<script>
var n = 0;
$("#d01").on("mousemove",function(){disp.textContent="何回でも発生する" + "(" + n++ + ")";});  // 何回でもイベント発生
$("#d02").one("mousemove",function(){disp.textContent="1回だけ(次は発生しない)";});         // 1回だけイベント発生
$("span").on("mouseleave", function(){disp.textContent=" ";});
</script>

また、上の例の jQuery の記述部分は jQuery を使用しなければ、次のように書き換えることもできます。

なお、[].slice.call は Array.prototype.slice.call と書くこともでき、querySelectorAll などの戻り値を Array オブジェクトに変換します。

var n = 0;
d01.addEventListener("mousemove",function(){disp.textContent="何回でも発生する" + "(" + n++ + ")";});  // 何回でもイベント発生
d02.addEventListener("mousemove",once);
var e = [].slice.call(document.querySelectorAll("span"));
e.forEach(function(e) { e.addEventListener("mouseleave", function(){disp.textContent=" ";}); });
function once() {
  disp.textContent="1回だけ(次は発生しない)";         // 1回だけイベント発生
  this.removeEventListener("mousemove",once);
}

文字列にマウスを重ねてください

実行例(jQuery 使用)
実行例(jQuery 未使用)

(1-2)イベントハンドラの削除(off)

on で設定したイベントハンドラを削除します。ただし、on で指定したイベント要素やイベントハンドラを指定しないと削除されません。

メソッド引数機能戻り値
off([イベント][,イベント要素],イベントハンドラ)イベント:イベント名(注1)
イベント要素:セレクタ(注2)
イベントハンドラ:関数
要素のイベントハンドラを削除するjQuery オブジェクト
注1)空白区切りで複数設定でき、名前空間も指定できる。
注2)on で指定したセレクタでないと削除されない
記述例
<div id="disp" style="background-color:yellow;width:10em;"> </div>

<span id="d01"><span>AAA</span> <span>BBB</span><span>CCC</span></span><br>
<!-- 以下略 -->

<script>
$("#d01").on("mousemove click", "span", set);
$("#d01").off();
$("#d02").on("mousemove click", "span", set);
$("#d02").off("mousemove");
$("#d03").on("mousemove", "span:eq(0)", set);  // span に個別で mousemove イベントを設定
$("#d03").on("mousemove", "span:eq(1)", set);
$("#d03").on("mousemove", "span:eq(2)", set);
$("#d03").off("mousemove", "span");              // 2番目の引数が一致しないので削除できない
$("#d03").off("mousemove", "span:eq(1)");
$("#d03").on("click", "span", set);            // span に一括で click イベントを設定
$("#d03").off("click", "span:eq(1)");            // 2番目の引数が一致しないので削除できない
$("#d04").on("mousemove", "span:eq(0)", set);  // span に個別で mousemove イベントを設定
$("#d04").on("mousemove", "span:eq(1)", xxx);
$("#d04").on("mousemove", "span:eq(2)", set);
$("#d04").off("mousemove", xxx);               // 一致するイベントハンドラを削除する

$("span").on("mouseleave", function(){disp.textContent=" ";});

function set(event) {
  disp.textContent= this.textContent + "(" + event.type + ")";
}
function xxx() {
  disp.textContent= "xxx";
}
</script>

また、上の例の jQuery の記述部分は jQuery を使用しなければ、次のように書き換えることもできます。

ただし、jQuery のイベントは独自に実現しています。jQuery 未使用 の例では javascript の機能のみを使用しているため、jQuery 使用 の例とは動作が違う部分があります(完全に一致していなくても削除できるようになっています)。なお、× が書かれているところが jQuery 使用 の例と違うところです。

なお、[].slice.call は Array.prototype.slice.call と書くこともでき、querySelectorAll などの戻り値を Array オブジェクトに変換します。

addEvents(d01, "span", ["mousemove","click"], set);
removeEvents(d01, "span", ["mousemove","click"], set);
addEvents(d02, "span", ["mousemove","click"], set);
removeEvents(d02, "span", ["mousemove"], set);
addEvents(d03, "span:nth-of-type(1)", ["mousemove"], set);      // span に個別で mousemove イベントを設定
addEvents(d03, "span:nth-of-type(2)", ["mousemove"], set);
addEvents(d03, "span:nth-of-type(3)", ["mousemove"], set);
//removeEvents(d03, "span", ["mousemove"], set);                // × d03 の span 子要素の mousemove をすべて削除する
removeEvents(d03, "span:nth-of-type(2)", ["mousemove"], set);
addEvents(d03, "span", ["click"], set);                         // span に一括で click イベントを設定
removeEvents(d03, "span:nth-of-type(2)", ["click"], set);       // × d03 の2番目の span の click イベントを削除する
addEvents(d04, "span:nth-of-type(1)", ["mousemove"], set);      // span に個別で mousemove イベントを設定
addEvents(d04, "span:nth-of-type(2)", ["mousemove"], xxx);
addEvents(d04, "span:nth-of-type(3)", ["mousemove"], set);
removeEvents(d04, "", ["mousemove"], xxx);                      // 一致するイベントハンドラを削除する

var e = [].slice.call(document.querySelectorAll("span"));
e.forEach(function(e) { e.addEventListener("mouseleave", function(){disp.textContent=" ";}); });

function addEvents(parent, child, events, handler) {
  let children = child==""?parent.childNodes:[].slice.call(parent.querySelectorAll(child));
  for (let i = 0 ; i < children.length ; i++) {
    for (let j in events) {
      children[i].addEventListener(events[j], handler);
    }
  }
}
function removeEvents(parent, child, events, handler) {
  let children = child==""?parent.childNodes:[].slice.call(parent.querySelectorAll(child));
  for (let i = 0 ; i < children.length ; i++) {
    for (let j in events) {
      children[i].removeEventListener(events[j], handler);
    }
  }
}

// 以下略


2番目の例は mousemove イベントは削除しましたが、click イベントは削除されていませんので、クリックするとイベントハンドラが実行されます。

実行例(jQuery 使用)
実行例(jQuery 未使用)

click.xxx のようにイベント名に名前空間を指定することができます。この場合は xxx が名前空間です。

名前空間を替えることによって同じイベント名でも異なるイベントとして区別することができます。

次の例は、"AAA" という文字列の click イベントに2つのイベントハンドラを設定しています。一つは背景色を青くするもので、もう一つは文字色を黄色にするものです。「on」ボタンで設定され、「off」ボタンで削除されます。

一つ目の例はイベントハンドラが同じ名前空間にありますので、off("click") によって二つのイベントハンドラとも削除されてしまいます。

二つ目の例はイベントハンドラが異なる名前空間にありますので、off("click.x2") で削除されるのは x2 のイベントハンドラだけです。

記述例
<span id="d01">AAA</span> <div class="switch" onclick="on1();">on</div> <div class="switch" onclick="off1();">off</div><br> 
<span id="d02">AAA</span> <div class="switch" onclick="on2();">on</div> <div class="switch" onclick="off2();">off</div><br> 

<script>
function on1() {            // 同じ名前空間
  $("#d01").on("click", backgroundColor);
  $("#d01").on("click", color);
}
function on2() {            // 異なる名前空間
  $("#d02").on("click.x1", backgroundColor);
  $("#d02").on("click.x2", color);
}
function off1() {
  off($("#d01"));
  $("#d01").off("click");    // click のイベントハンドラをすべて削除
}
function off2() {
  off($("#d02"));
  $("#d02").off("click.x2"); // x2 という名前空間の click のイベントハンドラを削除
}
function off(me) {
  me.css("background-color", "transparent");
  me.css("color", "black");
}

function backgroundColor() {    // 背景色を青くする
  $(this).css("background-color", "blue");
}
function color() {              // 文字色を黄色にする
  $(this).css("color", "yellow");
}
</script>

また、上の例の jQuery の記述部分は jQuery を使用しなければ、次のように書き換えることもできます。

function on1() {            // 同じ名前空間
  d01.addEventListener("click", backgroundColor, false);
  d01.addEventListener("click", color, false);
}
function on2() {            // 異なる名前空間
  d02.addEventListener("click", backgroundColor, false);
  d02.addEventListener("click", color, false);
}
function off1() {
  off(d01);
  d01.removeEventListener("click", backgroundColor, false);
  d01.removeEventListener("click", color, false);
}
function off2() {
  off(d02);
  d02.removeEventListener("click", color, false);
}
function off(me) {
  me.style.backgroundColor = "transparent";
  me.style.color = "black";
}

function backgroundColor() {    // 背景色を青くする
  this.style.backgroundColor = "blue";
}
function color() {              // 文字色を黄色にする
  this.style.color = "yellow";
}

ボタンをクリックした後に "AAA" という文字列をクリックしてみてください。

実行例(jQuery 使用)
実行例(jQuery 未使用)

(1-3)イベントの発生(trigger、triggerHandler)

イベントを発生させます。ただし、trigger ではイベントによってブラウザ本来の機能が実行されるのに対して、triggerHandler では実行されません。下の例での本来の機能とは、チェックボックスにチェックが付くことです。

また、trigger は対象要素すべてに有効ですが、triggerHandler は最初の一つしか有効になりません(イベントの伝播も起こりません)。

メソッド引数機能戻り値
trigger(イベント名[,引数])イベント名:イベントの名前
引数:イベントハンドラへの引数
対象要素に対してイベントを発生させるjQuery オブジェクト
trigger(イベントオブジェクト[,引数])イベントオブジェクト:イベントのオブジェクト(注)
引数:イベントハンドラへの引数
対象要素に対してイベントを発生させるjQuery オブジェクト
triggerHandler(イベント名[,引数])イベント名:イベントの名前
引数:イベントハンドラへの引数
対象要素に対してイベントを発生させる(ただし、ブラウザ本来の機能は実行させない)jQuery オブジェクト
triggerHandler(イベントオブジェクト[,引数])イベントオブジェクト:イベントのオブジェクト(注)
引数:イベントハンドラへの引数
対象要素に対してイベントを発生させる(ただし、ブラウザ本来の機能は実行させない)jQuery オブジェクト
注)イベントオブジェクトは $.Event() で生成する((3)イベント・オブジェクト を参照)

下の例では、trigger のときは3つのチェックボックスすべてにイベントが発生しチェックが付き、結果的に3つ目のチェックボックスにフォーカスが移り青くなります。しかし、triggerHandler は一つ目のチェックボックスだけにイベントが発生しますが、本来の機能であるチェックは付きません。ただし、枠が青くなっていることからイベントが発生していることは分かります。

また、この例ではイベントハンドラに文字列を引数として渡しています。イベントハンドラは受け取った文字列を title に設定しています。ただし、なぜか click イベントでは引数を受け取ることができないようです。

記述例
スタイルシート
<style>
input:focus {
  outline-style: solid;
  outline-color: cyan;
}
</style>

<input id="check1" type="checkbox"> <input id="check2" type="checkbox"> <input id="check3" type="checkbox"><br>
<div class="switch" onclick="trigger();">trigger</div> <div class="switch" onclick="triggerHandler();">triggerHandler</div>
<script>
$("input").on("mouseclick", function(evt, mess) { this.focus(); this.title=mess;});
$("div").on("mouseleave", function(){check1.checked=check2.checked=check3.checked=null;}); 
function trigger() {
  $("input").trigger("mouseclick", ["trigger"]);
}
function triggerHandler() {
  $("input").triggerHandler("mouseclick", ["triggerHandler"]);
}
</script>

また、上の例の jQuery の記述部分は jQuery を使用しなければ、次のように書き換えることもできます。

なお、[].slice.call は Array.prototype.slice.call と書くこともでき、querySelectorAll などの戻り値を Array オブジェクトに変換します。

createEvent はたいていのブラウザでサポートされていますが、initEvent は廃止予定となっています。

var e = [].slice.call(document.querySelectorAll("div"));
e.forEach(function(e){ e.addEventListener("mouseleave", function(){inp1.value=inp2.value=check3.checked=false;}); }); 

function focus(mess) {
  return function (event) {
    this.focus();
    this.title = mess;
    event.preventDefault();  // cancelable が true なら デフォルトの処理を行わない
  };
}

function trigger() {
  let e = [].slice.call(document.querySelectorAll("input"));
  e.forEach(function(e) { e.addEventListener("click", focus("trigger")); });
  e.forEach(function(e) { e.dispatchEvent(getEvent(true, false)); });
}
function triggerHandler() {
  let e = document.createEvent("HTMLEvents");
  e.addEventListener("click", focus("triggerHandler"));
  e.dispatchEvent(getEvent(false, true));
}

function getEvent(bubbles, cancelable) {
  return new MouseEvent("click", {"bubbles":bubbles, "cancelable":cancelable});
}
実行例(jQuery 使用)
実行例(jQuery 未使用)

(2)イベント

(2-1) マウス・イベント

メソッド引数機能戻り値
click([引数][,イベントハンドラ])引数:イベントハンドラへの引数
イベントハンドラ:関数
対象要素のイベントに対する処理を設定する

引数があるときは
on("xxxxx"[,引数][,イベントハンドラ]) と同じ

引数がないときは
trigger("xxxxx") と同じ

(xxxxx : click、dblclick などのイベント名)
jQuery オブジェクト
dblclick([引数][,イベントハンドラ])
mousedown([引数][,イベントハンドラ])
mouseup([引数][,イベントハンドラ])
mouseover([引数][,イベントハンドラ])
mouseout([引数][,イベントハンドラ])
mouseenter([引数][,イベントハンドラ])
mouseleave([引数][,イベントハンドラ])
mousemove([引数][,イベントハンドラ])
hover(イベントハンドラ[,イベントハンドラ])イベントハンドラ:関数mouseenter と mouseleave に対する処理を設定する
イベントハンドラが一つしか指定されていないときは同じ関数が呼ばれる
jQuery オブジェクト

文字列やボタンにマウスを重ねてください。

<div id="d"></div>
<div id="p"></div>    <!-- 黄色い四角 -->

<script>
$("body").mouseleave(clear);
$("#p").click(dispEvent);
$("#p").dblclick(dispEvent);
$("#p").mousedown(dispEvent);
$("#p").mouseup(dispEvent);
$("#p").contextmenu(dispEvent);
$("#p").mouseenter(dispEvent);
$("#p").mouseleave(dispEvent);
$("#p").mousemove(dispEvent);
$("#p").mouseover(dispEvent);
$("#p").mouseout(dispEvent);

var mousemoveCount = 0;
function clear() {
  mousemoveCount = 0;
  document.getElementById("d").textContent = "";
}
function dispEvent(event) {
  event.preventDefault();    // デフォルトの処理を行わない
  if (event.type == "mousemove") {
    if (++mousemoveCount > 1) {
      let s = document.getElementById("d").textContent;
      let n = s.lastIndexOf("(");
      document.getElementById("d").textContent = s.substring(0, n) + "(" + mousemoveCount + ") ";
    }
    else {
      document.getElementById("d").textContent += event.type + "(1) ";
    }
  }
  else {
    mousemoveCount = 0;
    document.getElementById("d").textContent += event.type + " ";
  }
}
</script>

また、上の例の jQuery の記述部分は jQuery を使用しなければ、次のように書き換えることもできます。

document.body.addEventListener("mouseleave", clear, false);
p.addEventListener("click", dispEvent, false);
p.addEventListener("dblclick", dispEvent, false);
p.addEventListener("mousedown", dispEvent, false);
p.addEventListener("mouseup", dispEvent, false);
p.addEventListener("contextmenu", dispEvent, false);
p.addEventListener("mouseenter", dispEvent, false);
p.addEventListener("mouseleave", dispEvent, false);
p.addEventListener("mousemove", dispEvent, false);
p.addEventListener("mouseenter", dispEvent, false);
p.addEventListener("mouseout", dispEvent, false);

// 以下略

実行例(jQuery 使用)
実行例(jQuery 未使用)

(2-2) キーボード・イベント

メソッド引数機能戻り値
keydown([引数][,イベントハンドラ])引数:イベントハンドラへの引数
イベントハンドラ:関数
対象要素のイベントに対する処理を設定する
引数があるときは
on("xxxxx"[,引数][,イベントハンドラ]) と同じ
引数がないときは
trigger("xxxxx") と同じ
(xxxxx : keydown、focus などのイベント名)
jQuery オブジェクト
keypress([引数][,イベントハンドラ])
keyup([引数][,イベントハンドラ])

下の入力欄で何かキーを押してください。押したときに keydown が発生し、文字キーの場合はそれに続いて keypress が発生します。そして、キーを離すと keyup が発生します。

<span id="d1"></span> <span id="d2"></span> <span id="d3"></span><br>
<input id="t" type="text">

<script>
$("#t").keydown(dispEvent);
$("#t").keypress(dispEvent);
$("#t").keyup(dispEvent);

var n = 1;
function clear() {
  n = 1;
  d1.textContent=d2.textContent=d3.textContent="";
}
function dispEvent(event) {
  if (event.type == "keydown")
    clear();
  document.getElementById("d" + n++).textContent=event.type;
}
</script>

また、上の例の jQuery の記述部分は jQuery を使用しなければ、次のように書き換えることもできます。

t.addEventListener("keydown", dispEvent, false);
t.addEventListener("keypress", dispEvent, false);
t.addEventListener("keyup", dispEvent, false);

// 以下略

実行例(jQuery 使用)
実行例(jQuery 未使用)

(2-3) フォーム・イベント

メソッド引数機能戻り値
focus([引数][,イベントハンドラ])引数:イベントハンドラへの引数
イベントハンドラ:関数
対象要素のイベントに対する処理を設定する

引数があるときは
on("xxxxx"[,引数][,イベントハンドラ]) と同じ

引数がないときは
trigger("xxxxx") と同じ

(xxxxx : keydown、focus などのイベント名)
jQuery オブジェクト
focusin([引数][,イベントハンドラ])
focusout([引数][,イベントハンドラ])
blur([引数][,イベントハンドラ])
select([引数][,イベントハンドラ])
change([引数][,イベントハンドラ])
submit([引数][,イベントハンドラ])

記述例
<div id="d1"></div>
<input id="text" type="text"><br>
<input id="search" type="search"><br>
<select id="select">
  <option value="0"></option>
  <option value="1" label="aaa">aaa</option>
  <option value="2" label="bbb">bbb</option>
  <option value="3" label="ccc">ccc</option>
</select>
<form id="form" onsubmit="return false;">
  <input type="submit" value="送信">
</form>
  
<script>
$("body").mouseleave(clear);
$("#text").focus(dispEvent);
$("#text").focusin(dispEvent);
$("#text").focusout(dispEvent);
$("#text").change(dispEvent);
$("#text").select(dispEvent);
$("#search").focus(dispEvent);
$("#search").focusin(dispEvent);
$("#search").focusout(dispEvent);
$("#search").change(dispEvent);
$("#search").select(dispEvent);
$("#select").focus(dispEvent);
$("#select").focusin(dispEvent);
$("#select").focusout(dispEvent);
$("#select").change(dispEvent);
$("#form").submit(dispEvent);

function clear() {
  d1.textContent=text.textContent=search.textContent=select.textContent="";
}
function dispEvent(event) {
  d1.textContent += event.type + " ";
}
</script>

また、上の例の jQuery の記述部分は jQuery を使用しなければ、次のように書き換えることもできます。

document.body.addEventListener("mouseleave", clear, false);
text.addEventListener("focus", dispEvent, false);
text.addEventListener("focusin", dispEvent, false);
text.addEventListener("focusout", dispEvent, false);
text.addEventListener("change", dispEvent, false);
text.addEventListener("select", dispEvent, false);
search.addEventListener("focus", dispEvent, false);
search.addEventListener("focusin", dispEvent, false);
search.addEventListener("focusout", dispEvent, false);
search.addEventListener("change", dispEvent, false);
search.addEventListener("search", dispEvent, false);
search.addEventListener("select", dispEvent, false);
select.addEventListener("focus", dispEvent, false);
select.addEventListener("focusin", dispEvent, false);
select.addEventListener("focusout", dispEvent, false);
select.addEventListener("change", dispEvent, false);
form.addEventListener("submit", dispEvent, false);

// 以下略

実行例(jQuery 使用)
実行例(jQuery 未使用)

(2-4) ウィンドウ・イベント

メソッド引数機能戻り値
resize([引数][,イベントハンドラ])引数:イベントハンドラへの引数
イベントハンドラ:関数
対象要素のイベントに対する処理を設定する
引数があるときは
on("xxxxx"[,引数][,イベントハンドラ]) と同じ
引数がないときは
trigger("xxxxx") と同じ
(xxxxx : keydown、focus などのイベント名)
jQuery オブジェクト
scroll([引数][,イベントハンドラ])
ready(イベントハンドラ)イベントハンドラ:関数DOM 要素が全てロードされた段階で実行させたい処理を設定する
13.3.1 主要部 (1) 関数の実行 を参照してください)
jQuery オブジェクト

記述例
<div id="d1"></div>
<div id="d2"></div>
<div id="d3"></div>

<script>
$(parent.window).resize(function(event) {dispEvent(event); size()});
$(document).scroll(function(event) {dispEvent(event); scroll()});

function dispEvent(event) {
  d1.textContent=event.type;
}
function size() {
  d2.textContent="(" + parent.window.innerWidth + "," + parent.window.innerHeight + ")";
}
function scroll() {
  d3.textContent="(" + this.window.pageYOffset + "," + this.window.pageXOffset + ")";
}
</script>

また、上の例の jQuery の記述部分は jQuery を使用しなければ、次のように書き換えることもできます。

parent.addEventListener("resize", function(event) {dispEvent(event); size()}, false);
document.addEventListener("scroll", function(event) {dispEvent(event); scroll()}, false);

// 以下略

下の例の枠にあるスクロールバーを移動させるか、ブラウザのサイズを変更してみてください。

実行例(jQuery 使用)
実行例(jQuery 未使用)

(3)イベント・オブジェクト

(3-1) イベント・オブジェクトの生成

メソッド引数機能戻り値
$.Event(イベント名[,引数])イベント名:発生させるイベントの名前
引数:イベントハンドラへの引数
イベントオブジェクトを作成するイベントオブジェクト

Event で生成したイベント・オブジェクトは trigger や triggerHandler でイベントとして発生させます。

イベントハンドラへ渡す引数は Event でも指定できますが、trigger や triggerHandler でも設定ができます。ただし、設定の方法や受け取り方が異なりますので注意してください。

ただし、なぜかチェックボックスには click イベントで引数を渡すことができません。undefined となってしまいます。しかし、mouseclick ならば渡すことができます。また、他の input 要素などへは click イベントでも引数を渡すことができます。

記述例
<input type="checkbox"><br>
<input type="radio"> <input type="text"> <select></select><textarea rows="1"></textarea> <input type="button" value="ボタン"><br>
<div class="switch" onclick="doClick();">click</div> <div class="switch" onclick="doMouseclick();">mouseclick</div>

<script>
$("input, select, textarea").on("click", function(event, mess) { this.title=event.mess + "|" + mess; });
$("input, select, textarea").on("mouseclick", function(event, mess) { this.title=event.mess + "|" + mess; });
var clickEvent = $.Event("click", {mess:"Event生成"});
var mouseclickEvent = $.Event("mouseclick", {mess:"Event生成"});

function doClick() {
  $("input, select, textarea").trigger(clickEvent, ["trigger"]);
}
function doMouseclick() {
  $("input, select, textarea").trigger(mouseclickEvent, ["trigger"]);
}
</script>

また、上の例の jQuery の記述部分は jQuery を使用しなければ、次のように書き換えることもできます。

[].slice.call は Array.prototype.slice.call と書くこともでき、querySelectorAll などの戻り値を Array オブジェクトに変換します。

なお、jQuery 未使用 の方では click イベントでもチェックボックスに引数が渡るようにしています。

ただし、イベント・オブジェクトに引数を設定する方法として initCustomEvent を使用していますが、このメソッドは廃止予定となっていますので使用しない方が良いでしょう。使用しない場合の代替方法や new MouseEvent() の場合の方法は分かりません。

var e = [].slice.call(document.querySelectorAll("input, select, textarea"));
e.forEach(function(e) { e.addEventListener("click", setTitle("listener")); });
e.forEach(function(e) { e.addEventListener("mouseclick", setTitle("listener")); });
var clickEvent = getEvent("click", {mess:"Event生成"});
var mouseclickEvent = getEvent("mouseclick", {mess:"Event生成"});

function doClick() {
  e.forEach(function(e) { e.dispatchEvent(clickEvent); });
}
function doMouseclick() {
  e.forEach(function(e) { e.dispatchEvent(mouseclickEvent); });
}

function setTitle(mess) {    // addEventListener で設定した データは引数で渡される
  return function(event) {
    this.title=event.detail.mess + "|" + mess;    // initCustomEvent で設定したデータは detail にある
  };
}
function getEvent(event, param) {
  let evt = document.createEvent("CustomEvent");
  evt.initCustomEvent(event, false, false, param);    // 廃止予定なので使用しない方が良い
  return evt;
}

最初は各要素の title 属性は設定されていませんが、click や mouseclick のボタンをクリックすると設定されます。

実行例(jQuery 使用)
再実行
実行例(jQuery 未使用)
再実行

(3-2) イベント・オブジェクトのプロパティ

プロパティ
eventObject.type発生したイベントの種類
eventObject.dataイベントハンドラに渡された情報
eventObject.pageXイベントが発生したX座標
eventObject.pageYイベントが発生したY座標
eventObject.timeStampイベントが発生した時間
eventObject.which押されたキーのコードやマウスのボタン
eventObject.result直前に実行したイベントハンドラが返した値
eventObject.namespacetrigger で送ったイベントの名前空間
eventObject.targetイベントが発生したDOM要素
eventObject.currentTargetバブリング(先祖方向への伝播)中のイベントが現在通過しているDOM要素
eventObject.delegateTarget調査範囲に設定されたDOM要素
eventObject.relatedTarget別のDOM要素に移動したときに、その前に存在していたDOM要素
注)eventObject : $.Event() で生成したイベントオブジェクト

t と書かれた緑色の四角にマウス関係のイベントが設定されています。マウスを動かしたりクリックしたりするとイベントのプロパティを取得できます。

「result」ボタンはデータの受け渡しです。data と result プロパティを表示しています。

「trigger」ボタンは名前空間です。namespase プロパティは trigger メソッドでイベントを発生させないと取得できません。

記述例
<div  id="p" class="box" style="background-color:yellow;">p
  <div  id="t" class="box" style="background-color:lightgreen;">t
    <div  id="c" class="box" style="background-color:lightcyan;">c</div>
  </div>
</div>

<div id="s1" class="switch">result</div>
<div id="s2" class="switch" onclick="trigger();">namespace</div>

<span id="d01"></span>
<!-- 以下略 -->

<script>
$("#t").click(dispEvent);
$("#t").dblclick(dispEvent);
$("#t").mousedown(dispEvent);
$("#t").mouseup(dispEvent);
$("#t").contextmenu(dispEvent);
$("#t").mouseenter(dispEvent);
$("#t").mouseleave(dispEvent);
$("#t").mousemove(dispEvent);
$("#t").mouseover(dispEvent);
$("#t").mouseout(dispEvent);
$("#t").mouseleave(clear);

$("#s1").on("click", {key:"aaa"}, on1).on("click", {key:"bbb"}, on2);
$("#t").on("click.xxx", function(event) { d13.textContent = event.namespace; });    // 名前空間

function on1(event) {
  return event.data.key;    // aaa
}
function on2(event) {
  d11.textContent = event.data.key;   // bbb
  d12.textContent = event.result;     // aaa
}
function trigger() {
  $("#t").trigger("click.xxx");
}

function dispEvent(event) {
  d01.textContent = event.type;
  d02.textContent = event.pageX;
  d03.textContent = event.pageY;
  let date = new Date(event.timeStamp);
  d04.textContent = date.toLocaleDateString() + " " + date.toLocaleTimeString();
  d05.textContent = event.which;
  d06.textContent = event.target.tagName + "#" + event.target.id;
  d07.textContent = event.currentTarget.tagName + "#" + event.currentTarget.id;
  d08.textContent = event.delegateTarget.tagName + "#" + event.delegateTarget.id;
  if (event.relatedTarget != null) {  // mousemove では null
    d09.textContent = event.relatedTarget.tagName + "#" + event.relatedTarget.id;
  }
}

function clear() {
  for (let i = 1 ; i <= 9 ; i++) {
    document.getElementById("d0" + i).textContent = "";
  }
  for (let i = 11 ; i <= 13 ; i++) {
    document.getElementById("d" + i).textContent = "";
  }
}
</script>

また、上の例の jQuery の記述部分は jQuery を使用しなければ、次のように書き換えることもできます。

ただし、namespace は jQuery を使用しない場合の javascript には存在しないので記述していません。

t.addEventListener("click", dispEvent, false);
t.addEventListener("dblclick", dispEvent, false);
t.addEventListener("mousedown", dispEvent, false);
t.addEventListener("mouseup", dispEvent, false);
t.addEventListener("contextmenu", dispEvent, false);
t.addEventListener("mouseenter", dispEvent, false);
t.addEventListener("mouseleave", dispEvent, false);
t.addEventListener("mousemove", dispEvent, false);
t.addEventListener("mouseover", dispEvent, false);
t.addEventListener("mouseout", dispEvent, false);
t.addEventListener("mouseleave", clear, false);

s1.addEventListener("click", on1({key:"aaa"}), false);
s1.addEventListener("CustomEvent", on2({key:"bbb"}), false);

function on1(map) {
  return function (event) {
    this.dispatchEvent(getEvent("CustomEvent", {key:map.key}));
  }
}
function on2(map) {
  return function (event) {
    d11.textContent = map.key;
    d12.textContent = event.detail.key;
  }
}

function getEvent(event, param) {
  let evt = document.createEvent("CustomEvent");
  evt.initCustomEvent(event, false, false, param);    // 廃止予定なので使用しない方が良い
  return evt;
}
実行例(jQuery 使用)
実行例(jQuery 未使用)

(3-3) イベント・オブジェクトのメソッド

メソッド引数機能戻り値
$.stopPropagation()なしバブリングを停止し、イベントの伝播を止めるなし
$.stopImmediatePropagation()なしバブリングを停止し、さらに他に設定されたイベントハンドラの処理も停止するなし
$.preventDefault()なしブラウザの持つデフォルトの機能を実行しないようにするなし
$.isPropagationStopped()なしイベントの伝播が止まったか否かを調査するtrue:止まった、false:止まっていない
$.isImmediatePropagationStopped()なしイベントオブジェクトがstopImmediatePropagationメソッドを実行したか否かを調査するtrue:実行した、false:実行していない
$.isDefaultPrevented()なしイベントオブジェクトがpreventDefaultメソッドを実行したか否かを調査するtrue:実行した、false:実行していない
注)eventObject : $.Event() で生成したイベントオブジェクト

○ stopPropagation、stopImmediatePropagation、isPropagationStopped、isImmediatePropagationStopped

下の例で、色のついた四角の部分をクリックすると2つのイベントが発生します。"イベント →" の横に数字を出す、先に送信されるイベントと、四角を赤っぽくする、後から送信されるイベントです。

stopPropagation で数字を指定するとその数字のところでイベントの伝播が共に終了します(空白にすると最後まで伝播します)。

しかし、stopImmediatePropagation にチェックを入れると、イベントの伝播が共に終了するだけでなく、その後のイベントもその時点で終了します。下の例では、"イベント →" の横に数字を出すイベントハンドラで stopImmediatePropagation() を実行していますから、その後の四角を赤っぽくするイベントは送信されません。つまり、stopImmediatePropagation にチェックを入れるか入れないかで、赤っぽくなる範囲が異なります。

記述例
<label id="stop">stopPropagation
<select id="s">
<option value="dx"> </option>
<option value="d4">4</option>
<option value="d3" selected>3</option>
<option value="d2">2</option>
<option value="d1">1</option>
</select>
</label>
<div id="d4" class="box" style="background-color:lavenderblush;">4
<div id="d3" class="box" style="background-color:yellow;">3
<div id="d2" class="box" style="background-color:lightgreen;">2
<div id="d1" class="box" style="background-color:lightcyan;">1
</div></div></div></div><br>
<input type="checkbox" onclick="flagStopImmediatePropagation = this.checked"><br>

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

<script>
var flagStopImmediatePropagation = false;   // stopImmediatePropagation にチェックが付けられているかどうか
var n = 1;
function clear() {
  n = 1;
  $("#d11").text("");
  $("#d12").text("");
  $("#d13").text("");
  $("#d14").text("");
  $("#d21").text("");
  $("#d22").text("");
  $("#d4").css("background-color", "lavenderblush");
  $("#d3").css("background-color", "yellow");
  $("#d2").css("background-color", "lightgreen");
  $("#d1").css("background-color", "lightcyan");
}
function click(element) {
  return function(event) {
    $("#d1" + n++).text(element);
    if (s.value == "d" + element) {
      if (flagStopImmediatePropagation == true) {
        event.stopImmediatePropagation();
      }
      else {
        event.stopPropagation();
      }
    }
    $("#d21").text(event.isPropagationStopped());
    $("#d22").text(event.isImmediatePropagationStopped());
  }
}
function click2(element) {
  return function() {
    $("#d" + element).css("background-color", "pink");
  }
}

$("#d1, #d2, #d3").mouseenter(clear);
$("#d1, #d2, #d3, #d4").mouseleave(clear);
$("#d1").click(click("1")).click(click2("1"));
$("#d2").click(click("2")).click(click2("2"));
$("#d3").click(click("3")).click(click2("3"));
$("#d4").click(click("4")).click(click2("4"));
</script>

また、上の例の jQuery の記述部分は jQuery を使用しなければ、次のように書き換えることもできます。

var flagStopPropagation = false;            // stopPropagation() が実行されたかどうか
var flagStopImmediatePropagation = false;   // stopImmediatePropagation にチェックが付けられているかどうか
var n = 1;
function clear() {
  n = 1;
  d11.textContent="";
  d12.textContent="";
  d13.textContent="";
  d14.textContent="";
  d21.textContent="";
  d22.textContent="";
  d4.style.backgroundColor = "lavenderblush";
  d3.style.backgroundColor = "yellow";
  d2.style.backgroundColor = "lightgreen";
  d1.style.backgroundColor = "lightcyan";
  flagStopPropagation = false;
}
function click(element) {
  return function(element) {
    document.getElementById("d1" + n++).textContent = element;
    if (s.value == "d" + element) {
      element.stopPropagation();
      flagStopPropagation = true;
    }
    d21.textContent = flagStopPropagation;
    d22.textContent = flagStopImmediatePropagation;
  }
}
function click2(element) {
  return function() {
    if (flagStopPropagation == false || flagStopImmediatePropagation == false)
      document.getElementById("d" + element).style.backgroundColor = "pink";
  }
}

d1.addEventListener("mouseenter", clear);
d2.addEventListener("mouseenter", clear);
d3.addEventListener("mouseenter", clear);
d1.addEventListener("mouseleave", clear);
d2.addEventListener("mouseleave", clear);
d3.addEventListener("mouseleave", clear);
d4.addEventListener("mouseleave", clear);
d1.addEventListener("click", click("1"));
d1.addEventListener("click", click2("1"));
d2.addEventListener("click", click("2"));
d2.addEventListener("click", click2("2"));
d3.addEventListener("click", click("3"));
d3.addEventListener("click", click2("3"));
d4.addEventListener("click", click("4"));
d4.addEventListener("click", click2("4"));
実行例(jQuery 使用)
実行例(jQuery 未使用)

○ preventDefault、isDefaultPrevented

preventDefault は、イベントが発生した要素のデフォルトの処理をキャンセルします。

例えば、チェックボックスではチェックが付いたり外れたりですし、テキストボックスでは入力された文字の表示ですし、アンカーでは指定されたドキュメントへの遷移(下の例では、アラートの表示)です。

preventDefault のチェックがついていない状態では、それぞれの要素はデフォルトの処理を行いますが、チェックを付けた状態ではそれらの処理は行われません。

記述例
preventDefault <input type="checkbox" onclick="flagPreventDefault = this.checked"><span id="d01"></span><br>

<div id="test">
  <input type="checkbox"><br>
  <input type="text"><br>
  <a href="javascript:alert('デフォルトの処理');">アンカー</a>
</div>

<script>
var flagPreventDefault = false;
function clear() {
  $("#d01").text("");
}
function preventDefault(event) {
  clear();
  if (flagPreventDefault == true) {
    event.preventDefault();
  }
  $("#d01").text(event.type);
  $("#d11").text(event.isDefaultPrevented());
}

$("#test input").click(preventDefault);
$("#test input[type='text']").keydown(preventDefault);
$("#test a").click(preventDefault);
</script>

また、上の例の jQuery の記述部分は jQuery を使用しなければ、次のように書き換えることもできます。

[].slice.call は Array.prototype.slice.call と書くこともでき、querySelectorAll などの戻り値を Array オブジェクトに変換します。

var flagPreventDefault = false;   // preventDefault にチェックが付けられているかどうか
function clear() {
  d01.textContent = "";
}
function preventDefault(event) {
  clear();
  if (flagPreventDefault == true) {
    event.preventDefault();
  }
  d01.textContent = event.type;
  d11.textContent = flagPreventDefault;
}

var e = [].slice.call(document.querySelectorAll("#test input"));
e.forEach(function(e){e.addEventListener("click", preventDefault);});
e = [].slice.call(document.querySelectorAll("#test input[type='text']"));
e.forEach(function(e){e.addEventListener("keydown", preventDefault);});
e = [].slice.call(document.querySelectorAll("#test a"));
e.forEach(function(e){e.addEventListener("click", preventDefault);});
実行例(jQuery 使用)
実行例(jQuery 未使用)

13.3.10  コールバック

Callbacks で生成したコールバック・オブジェクトに、複数のコールバック関数を add で登録し、fire や fireWith などで実行します。

(1)コールバック・オブジェクト

コールバック関数を複数登録し、管理するためのオブジェクトです。

(1-1)コールバック・オブジェクトの生成

メソッド引数機能戻り値
$.Callbacks([フラグ])フラグ:コールバック・オブジェクトを生成するためのオプション
(空白区切りで複数指定できる)
オプション意味
once一度しか実行しないようにする
unique同じコールバック関数を重複して追加しないようにする
stopOnFalsefalse を返すと以降のコールバック関数の実行をキャンセルする
memoryadd でコールバック関数を格納したら、即座に、引数など直前に実行した設定で実行する
コールバック・オブジェクトを作成するコールバックオブジェクト

引数を指定しないで生成したコールバック・オブジェクトでは、同じコールバック関数を何回でも実行( fire )できますし、同じコールバック関数を何回でも登録( add )できます。また、コールバック関数が false を返しても実行はキャンセルされませんし、fire() をしなければコールバック関数は実行されません。

それに対して、引数を指定すると下の例では次のようになります(背景色の黄色い部分が動作の異なるところです)。

oncefire() を2回行っていますが、1回しか実行されません。
uniqueexec を2回 add() していますが、fire() をしても1回しか実行されません。
stopOnFalsefalse を返す execFalse を実行したので、その後の exec は実行されません。
memoryexec2 は add しているだけですが、直前に実行した exec と同じ引数(d4, "A")を持って実行されます。
記述例
<span id="d01"></span> <span id="d02"></span> <span id="d03"></span> <span id="d04"></span><br>    <!-- なし -->
<span id="d11"></span> <span id="d12"></span> <span id="d13"></span> <span id="d14"></span><br>    <!-- once -->
<!-- 以下略 -->

<script>
function execute(flag, d) {
  let d1 = document.getElementById(d + "1");
  let d2 = document.getElementById(d + "2");
  let d3 = document.getElementById(d + "3");
  let d4 = document.getElementById(d + "4");
  let cb = $.Callbacks(flag);
  cb.add(exec);
  cb.fire(d1, "1"); cb.fire(d1, "2");  // 同じコールバック関数(exec)の実行
  cb = $.Callbacks(flag);
  cb.add(exec); cb.add(exec);
  cb.fire(d2, "A");                    // 同じコールバック関数(exec)の登録
  cb = $.Callbacks(flag);
  cb.add(execFalse);
  cb.add(exec);
  cb.fire(d3, "A");                    // false を返した execFalse 後の exec の実行
  cb = $.Callbacks(flag);
  cb.add(exec);
  cb.fire(d4, "A");
  cb.add(exec2);                       // コールバック関数(exec2)の登録にみでの実行
}

execute("", "d0");            // 通常実行
execute("once", "d1");        // 重複実行の不可
execute("unique", "d2");      // 重複登録の不可
execute("stopOnFalse", "d3"); // return false での実行キャンセル
execute("memory", "d4");      // 前回の設定での実行

function exec(e, mess) {
  e.textContent += mess + " ";
}
function execFalse(e) {
  e.textContent += "X ";
  return false;
}
function exec2(e, mess) {
  e.textContent += "(" + mess + ") ";
}
</script>

また、上の例の jQuery の記述部分は jQuery を使用しなければ、次のように書き換えることもできます。

ただし、オプションを複数指定したときなど、厳密には同じではない(かもしれないなぁ~)と思います。

class Callbacks {
  constructor(flag) {
    this.flag = flag;
    this.stop = false;
    this.args = null;
    this.funcList = new Array();
  }
  add(func) {
    let self = this;
    let flist = Array.isArray(func) ? func : [func];
    flist.forEach( function(f) { self._addLoop(f); });
  }
  _addLoop(func) {
    let unique = true;
    if (this.flag == "unique") {
      unique = this.funcList.every(function(f) { return !(f.func == func); });
    }
    if (unique)
      this.funcList.push({"func":func, "count":0});
    if (this.flag == "memory" && this.args != null)
      func.apply(null, this.args);
  }
  fire() {
    let self = this;
    this.args = arguments;
    let result = false;
    self.funcList.forEach(function(f) {
      if (self.stop == true)
        return;
      if (self.flag != "once" || f.count == 0) {
        result = f.func.apply(null, self.args);
        f.count++;
      }
      if (self.flag == "stopOnFalse") {
        self.stop = result == false;
      }
    });
  }
}

function execute(flag, d) {
  let d1 = document.getElementById(d + "1");
  let d2 = document.getElementById(d + "2");
  let d3 = document.getElementById(d + "3");
  let d4 = document.getElementById(d + "4");

  let cb = new Callbacks(flag);
  cb.add(exec);
  cb.fire(d1, "1"); cb.fire(d1, "2");  // 同じコールバック関数(exec)の実行
  cb = new Callbacks(flag);
  cb.add(exec); cb.add(exec);
  cb.fire(d2, "A");                    // 同じコールバック関数(exec)の登録
  cb = new Callbacks(flag);
  cb.add(execFalse);
  cb.add(exec);
  cb.fire(d3, "A");                    // false を返した execFalse 後の exec の実行
  cb = new Callbacks(flag);
  cb.add(exec);
  cb.fire(d4, "A");
  cb.add(exec2);                       // コールバック関数(exec2)の登録にみでの実行
}

// 以下略

実行例(jQuery 使用)
実行例(jQuery 未使用)

(1-2)コールバック関数の管理

メソッド引数機能戻り値
add(コールバック関数)コールバック関数:追加したい関数
(配列にして複数指定できる)
コールバック関数をコールバックオブジェクトに追加するコールバックオブジェクト
remove(コールバック関数)コールバック関数:削除したい関数
(配列にして複数指定できる)
コールバック関数をコールバックオブジェクトから削除するコールバックオブジェクト
empty()なしコールバックオブジェクトを空にするコールバックオブジェクト
has(コールバック関数)コールバック関数:存在を調べたい関数コールバック関数がコールバックオブジェクトに存在するかどうか調べる(注)true:存在する、false:存在しない
lock()なしコールバックオブジェクトの変更、コールバック関数の呼び出しを無効にするコールバックオブジェクト
locked()なしコールバックリストがロックされているかどうか調べるtrue:されている、false:されていない
注)lock されていると、コールバック関数が存在していても false が返る

lock 後は、コールバック関数が存在していても has は false を返すようです(背景色が赤っぽいところ)。

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

<script>
var cb = $.Callbacks();
cb.add([exec, exec2]);
cb.textContent = cb.has(exec);
d02.textContent = d01.has(exec2);
cb.remove(exec);
d11.textContent = cb.has(exec);
d12.textContent = cb.has(exec2);
cb.empty();
d21.textContent = cb.has(exec);
d22.textContent = cb.has(exec2);
cb.add(exec);
d31.textContent = cb.has(exec);
d32.textContent = cb.has(exec2);
cb.lock();
cb.add(exec2);                     // lock 後に add を行っても追加されない
d41.textContent = cb.locked();        // lock 後の状態
d51.textContent = cb.has(exec);
d52.textContent = cb.has(exec2);


function exec(e, mess) {
  e.textContent += mess + " ";
}
function exec2(e, mess) {
  e.textContent += "(" + mess + ") ";
}
</script>

また、上の例の jQuery の記述部分は jQuery を使用しなければ、次のように書き換えることもできます。

class Callbacks {
  constructor(flag) {
    this.flag = flag;
    this.stop = false;
    this.lockedF = false;
    this.args = null;
    this.funcList = new Array();
  }
  add(func) {
    let self = this;
    let flist = Array.isArray(func) ? func : [func];
    flist.forEach( function(f) { self._addLoop(f); });
  }
  _addLoop(func) {
    let unique = true;
    if (this.flag == "unique") {
      unique = this.funcList.every(function(f) { return !(f.func == func); });
    }
    if (unique)
      this.funcList.push({"func":func, "count":0});
    if (this.flag == "memory" && this.args != null)
      func.apply(null, this.args);
  }
  has(func) {
    if (this.lockedF == true)
      return false;
    return this.funcList.some(function(f) { return f.func == func; });
  }
  remove(func) {
    let self = this;
    let flist = Array.isArray(func) ? func : [func];
    flist.forEach(function(f) { self._removeLoop(f); });
  }
  _removeLoop(func) {
    this.funcList.some(function(f, i, list) { if (f.func==func) list.splice(i, 1); });
  }
  empty() { this.funcList.splice(0); }
  lock() {  this.lockedF = true; }
  locked() { return this.lockedF; }
}

let cb = new Callbacks();
cb.add([exec, exec2]);
d01.textContent = cb.has(exec);
d02.textContent = cb.has(exec2);

// 以下略

実行例(jQuery 使用)
実行例(jQuery 未使用)

(1-3)コールバック関数の実行

メソッド引数機能戻り値
fire([引数,[引数, ...]])引数:コールバック関数に渡す引数
(, で区切って複数指定できる)
コールバックオブジェクト内のコールバック関数を実行するコールバックオブジェクト
fireWith(thisObject[,引数])thisObject:コールバック関数で this として扱われる値
引数:コールバック関数に渡す引数(配列)
コールバックオブジェクト内のコールバック関数を実行するコールバックオブジェクト
fired()なしコールバックオブジェクト内のコールバック関数が実行されたかどうかを調べるtrue:どれか一つでも実行された
false:実行されていない

記述例
<span id="d01"></span> <span id="d02"></span> <span id="d03"></span><br>
<span id="d11"></span> <span id="d12"></span> <span id="d13"></span><br>

<script>
var cb = $.Callbacks();
cb.add(exec);
d01.textContent = cb.fired();
cb.fire(d02, "A", "B");
d03.textContent = cb.fired();
cb = $.Callbacks();
cb.add(execWith);
d11.textContent = cb.fired();
cb.fireWith(d12, ["A", "B"]);
d13.textContent = cb.fired();

function exec(e, arg1, arg2) {
  e.textContent = arg1 + " " + arg2;
}
function execWith(arg1, arg2) {
  this.textContent = arg1 + " " + arg2;
}
</script>

また、上の例の jQuery の記述部分は jQuery を使用しなければ、次のように書き換えることもできます。

class Callbacks {
  constructor(flag) {
    this.flag = flag;
    this.stop = false;
    this.lockedF = false;
    this.args = null;
    this.firedF = false;
    this.funcList = new Array();
  }
  add(func) {
    let self = this;
    let flist = Array.isArray(func) ? func : [func];
    flist.forEach( function(f) { self._addLoop(f); });
  }
  _addLoop(func) {
    let unique = true;
    if (this.flag == "unique") {
      unique = this.funcList.every(function(f) { return !(f.func == func); });
    }
    if (unique)
      this.funcList.push({"func":func, "count":0});
    if (this.flag == "memory" && this.args != null)
      func.apply(null, this.args);
  }
  fire() { this._fire(null, arguments); }
  fireWith() { this._fire(arguments[0], arguments[1]); }
  _fire(thisObj, args) {
    let self = this;
    let result = false;
    this.args = arguments;
    this.funcList.forEach(function(f) {
      if (self.stop == true)
        return;
      if (self.flag != "once" || f.count == 0) {
        result = f.func.apply(thisObj, args);
        f.count++;
        self.firedF = true;
      }
      if (self.flag == "stopOnFalse") {
        self.stop = result == false;
      }
    });
  }
  fired() { return this.firedF; }
}

let cb = new Callbacks();
cb.add(exec);

// 以下略

実行例(jQuery 使用)
実行例(jQuery 未使用)

13.3.11  非同期処理

Deferred で生成したオブジェクトは、アニメ処理や通信処理のような非同期処理を監視し管理しやすくします。

つまり、Deferred で生成したオブジェクトに、正常終了したときの処理( done )と異常終了したときの処理( fail )を設定しておき、非同期に処理を実行します。そして、resolve() を実行したら正常終了したときの処理が、reject() を実行したら異常終了したときの処理が自動的に実行されるようになります。

ただし、通常は、その際に外部から簡単に正常終了や異常終了の変更をされないよう、Promise オブジェクトを Deferred オブジェクトから作成して利用します。

なお、Javascript にはやはり非同期処理を行う Promise オブジェクトが存在していますが、それとは別のオブジェクトです。

(1)非同期処理オブジェクト

遅延処理を実行するためのオブジェクトです。Deferred オブジェクトPromise オブジェクトがあります。

非同期処理オブジェクトは、処理の状態に応じて以下の3つがあります。

pending処理が完了していない状態。progress() で実行する処理を設定できます。
resolved処理が正常に終了した状態。done() で処理の完了時に実行する処理を設定できます。resolve() などでこの状態になります。
rejected処理中に問題が発生して中断した状態。fail() メソッドで中断時に実行する処理を設定できます。reject() などでこの状態になります。

状態の変化は、「pending→resolved(正常終了)」か「pending→rejected(異常終了)」の2つだけです。一度変化したら元には戻りません。

(1-1)非同期処理オブジェクトの生成

メソッド引数機能戻り値
$.Deferred([関数])関数:Deferred オブジェクトを作成する前に実行したい処理Deferred オブジェクトを作成するDeferred オブジェクト
$.when([非同期処理[, ...]])非同期処理:Deferred オブジェクト などPromise オブジェクトを作成する(指定された非同期処理がすべて終了したら、正常・異常処理が行われる)Promise オブジェクト
Deferredオブジェクト.promise([対象])対象:Object オブジェクトDeferred オブジェクトから Promise オブジェクトを作成する
対象が指定されている場合はそのオブジェクトを Promise オブジェクトとする
Promise オブジェクト
jQueryオブジェクト.promise([タイプ][,対象])タイプ:監視に必要なキュータイプ(規定値:fx)

対象:promiseメソッドを割り当てるオブジェクト
jQuery オブジェクトから Promise オブジェクトを作成する
対象が指定されている場合はそのオブジェクトを Promise オブジェクトとする
Promise オブジェクト

○ $.Deferred

$.Deferred() は、遅延実行をするためのオブジェクトを生成します。そのとき実行したい関数があれば $.Deferred() の引数として指定できます。

下の例は、5秒以内にチェックを付けると、resolve() が実行され正常終了したときの処理 done() に設定された関数("OK" が表示される)が呼び出されます。それに対して、チェックと付けないと、reject() が実行され異常終了したときの処理 fail() に設定された関数("遅い" が表示される)が呼び出されます。

記述例
<span id="count"></span> <input id="cb" type="checkbox"></span><br>
<span id="d01"></span><br>

<script>
var n;
var df = $.Deferred(init);
df.done(function() { d01.textContent = "OK"; });
df.fail(function() { d01.textContent = "遅い"; });

var timer = window.setInterval(countDown, 1000);

function countDown() {
  set();
  if (cb.checked) {
    df.resolve();                      // done() 呼び出し
    window.clearInterval(timer);
  }
  if (n < 0) { 
    df.reject();                       // fail() 呼び出し
    window.clearInterval(timer);
  }
}

function init() {
  n = 5;
  set();
  cb.checked = false;
}
function set() {
  count.textContent = n--;
}
</script>

また、上の例の jQuery の記述部分は jQuery を使用しなければ、次のように書き換えることもできます。

class Deferred {
  constructor(func) {
    this.promiseObject = new Promise();
    if (func != undefined) func();
    return this;
  }
  done(args) { this.promiseObject.done(args); }
  fail(args) { this.promiseObject.fail(args); }
  resolve() { this.promiseObject.funcDone.forEach(function(f) { f(); }); }
  reject() { this.promiseObject.funcFail.forEach(function(f) { f(); }); }
}
class Promise {
  constructor() {
    this.funcDone = [];
    this.funcFail = [];
  }
  done() {
    this.funcDone = this._concat(this.funcDone, arguments);
    return this;
  }
  fail() {
    this.funcFail = this._concat(this.funcFail, arguments);
    return this;
  }
  _concat(funcList, args) {
    if (args.length > 0) {
      for (var i in args)
      funcList = funcList.concat(args[i]);
    }
    else {
      funcList = funcList.concat(args);
    }
    return funcList;
  }
}

let n;
let df = new Deferred(init);
df.done(function() { d01.textContent = "OK"; });
df.fail(function() { d01.textContent = "遅い"; });

// 以下略

実行例(jQuery 使用)
再実行
実行例(jQuery 未使用)
再実行

○ $.when

引数に指定した Deferred オブジェクトなどがすべて成功(resolve() を実行)したら done() を実行し、一つでも失敗(reject() を実行)したら fail() を実行するような Promise オブジェクトを返します。

次の例は、3つの横に伸びていく帯と時間切れを監視するタイムアップの全部で4つの Deferred オブジェクトを引数にしています。

帯オブジェクトは自身の伸長が止まると resolve() を実行します。タイムアップ・オブジェクトは時間切れになったとき、すでにすべての帯オブジェクトの伸長が止まっていると resolve() を実行します。その結果、4つのオブジェクト共に resolve() を実行することになるので、done() が実行されます。しかし、帯オブジェクトがひとつでも伸長し続けているとタイムアップ・オブジェクトは reject() を実行しますので、fail() が実行されます。

記述例
<span id="d01"></span><br>
<div id="g1" style="background-color:lavenderblush;width:0px;"><br></div>
<div id="g2" style="background-color:lightgreen;width:0px;"><br></div>
<div id="g3" style="background-color:lightcyan;width:0px;"><br></div>

<script>
var g = [g1, g2, g3];
var obj1 = {count : 0};
var obj2 = {count : 0};
var obj3 = {count : 0};
var obj = [obj1, obj2, obj3];
for (let i in obj) init(i)
var df1 = $.Deferred();
var df2 = $.Deferred();
var df3 = $.Deferred();
var df = [df1, df2, df3];
var dfx = $.Deferred();

d01.textContent = "";
$.when(df1,df2,df3,dfx).done(function() { d01.textContent = "成功"; })
                       .fail(function() { d01.textContent = "失敗"; });

var timer1 = window.setInterval(process, 100, 0);
var timer2 = window.setInterval(process, 100, 1);
var timer3 = window.setInterval(process, 100, 2);
var timer = [timer1, timer2, timer3];
window.setTimeout(timeup, 4000);

function process(n) {
  g[n].style.width = (parseInt(g[n].style.width) + 5) + "px";
  if (--obj[n].count <= 0) {
    df[n].resolve();
    window.clearInterval(timer[n]);
  }
}
function timeup() {
  for(var i = 0 ; i < obj.length ; i++) {
    if (obj[i].count > 0) {
      dfx.reject();
      return;
    }
  }
  dfx.resolve()
}

function init(n) {
  obj[n].count = parseInt(Math.random() * 35) + 16;
}
</script>

また、上の例の jQuery の記述部分は jQuery を使用しなければ、次のように書き換えることもできます。

class When {
  constructor() {
    this.promiseObject = new Promise();
    this.promiseObject.setup(arguments);
    for (let i in arguments) {
      arguments[i].promiseObject = this.promiseObject;
  }
  return this.promiseObject;
}

class Promise {
  constructor() {
    this.doneF = 0;
    this.funcDone = [];
    this.funcFail = [];
  }
  done() {
    this.funcDone = this._concat(this.funcDone, arguments);
    return this;
  }
  fail() {
    this.funcFail = this._concat(this.funcFail, arguments);
    return this;
  }
  _concat(funcList, args) {
    if (args.length > 0) {
      for (let i in args)
        funcList = funcList.concat(args[i]);
    }
    else {
      funcList = funcList.concat(args);
    }
    return funcList;
  }
  setup(args) {
    let alen = args.length;
    for (let i in args) {
      args[i].resolve =
          function() {
            if (++this.promiseObject.doneF >= alen)
              this.promiseObject.funcDone.forEach(function(f) { f(); });
          }
      args[i].reject =
          function() {
            this.promiseObject.funcFail.forEach(function(f) { f(); });
          }
    }
  }
}

var g = [g1, g2, g3];
var obj1 = {count : 0};
var obj2 = {count : 0};
var obj3 = {count : 0};
var obj = [obj1, obj2, obj3];
for (let i in obj) init(i)
var df1 = new Deferred();
var df2 = new Deferred();
var df3 = new Deferred();
var df = [df1, df2, df3];
var dfx = new Deferred();

d01.textContent = "";
new When(df1,df2,df3,dfx).done(function() { d01.textContent = "成功"; })
                         .fail(function() { d01.textContent = "失敗"; });


// 以下略(Deferred は $.Deferred のところを参照してください)

実行例(jQuery 使用)
再実行
実行例(jQuery 未使用)
再実行

○ Deferred オブジェクト.promise

Promise オブジェクトは Deferred オブジェクトのメソッドのうち、追加のハンドラーや、状態を判定するメソッド(then, done, fail, always, progress, state) のみ公開し、状態を決定するメソッド (resolve, reject, notify, resolveWith, rejectWith, notifyWith) は公開しません。

引数を指定していない場合は Promise オブジェクトを新しく作成しますが、引数を指定した場合は Promise オブジェクトを新しく作成するのではなく、引数で指定したオブジェクトにメソッドを追加します(次の例は、3つの横に伸びていく帯がありますが、その3つ目が引数を指定した例です)。

記述例
<div id="g1" style="background-color:lavenderblush;width:0px;"><br></div>
<div id="g2" style="background-color:lightgreen;width:0px;"><br></div>
<div id="g3" style="background-color:lightcyan;width:0px;"><br></div>

<script>
var g = [g1, g2, g3];
var obj1 = {count : 0};
var obj2 = {count : 0};
var obj3 = {count : 0};
var obj = [obj1, obj2, obj3];
var df1 = $.Deferred(init(0));
var df2 = $.Deferred(init(1));
var df3 = $.Deferred();
var df = [df1, df2, df3];
var objx = new Object();
init(2);

df1.promise().done(function() { g1.textContent = "勝ち"; })
             .fail(function() { g1.textContent = "負け"; });
df2.promise().done(function() { g2.textContent = "勝ち"; })
             .fail(function() { g2.textContent = "負け"; });
df3.promise(objx);                         // 普通のオブジェクトを Promise オブジェクトにする
objx.done(function() { g3.textContent = "勝ち"; })
    .fail(function() { g3.textContent = "負け"; });

var timer1 = window.setInterval(process, 100, 0);
var timer2 = window.setInterval(process, 100, 1);
var timer3 = window.setInterval(process, 100, 2);
var timer = [timer1, timer2, timer3];

function process(n) {
  g[n].style.width = (parseInt(g[n].style.width) + 5) + "px";
  if (--obj[n].count <= 0) {
    window.clearInterval(timer[n]);
    for (let i in obj) {
      if (obj[i].count > 0) {
        df[n].reject();
        return;
      }
    }
    df[n].resolve();
  }
}

function init(n) {
  obj[n].count = parseInt(Math.random() * 35) + 16;
}
</script>

また、上の例の jQuery の記述部分は jQuery を使用しなければ、次のように書き換えることもできます。

class Deferred {
  constructor(func) {
    this.pobj = this.promiseObject = new Promise();
    if (func != undefined) func();
    return this;
  }
  promise(obj) {
    let self = this;
    if (obj != undefined) {
      obj.done = function(func) { obj.funcDone = self.pobj._concat([], func); return obj; }
      obj.fail = function(func) { obj.funcFail = self.pobj._concat([], func); return obj; }
      this.promiseObject = obj;
    }
    return this.promiseObject;
  }
  done(args) { this.promiseObject.done(args); }
  fail(args) { this.promiseObject.fail(args); }
  resolve() { this.promiseObject.funcDone.forEach(function(f) { f(); }); }
  reject() { this.promiseObject.funcFail.forEach(function(f) { f(); }); }
}

var g = [g1, g2, g3];

// 以下略(Promise は $.when のところを参照してください)

実行例(jQuery 使用)
再実行
実行例(jQuery 未使用)
再実行

(1-2)非同期処理の設定

正常終了時(resolve)、異常終了時(reject)あるいは、処理が完了していないとき(pending)に実行する処理を設定します。

なお、これらのメソッドは Deferred オブジェクトのメソッドです。

メソッド引数機能戻り値
always([関数[, ...]])関数:実行したい処理resolve、reject のいずれの場合でも、実行したいコールバック関数を指定するDeferred オブジェクト
done(関数[, ...])関数:実行したい処理resolve の場合に、実行したいコールバック関数を指定するDeferred オブジェクト
fail(関数[, ...])関数:実行したい処理reject の場合に、実行したいコールバック関数を指定するDeferred オブジェクト
progress(関数[, ...])関数:実行したい処理pending の場合に、実行したいコールバック関数を指定するDeferred オブジェクト
then(done関数[,fail関数[,progress関数]])関数:実行したい処理resolve、reject、pending のそれぞれの場合に、実行したいコールバック関数を指定するDeferred オブジェクト
注)引数の関数は、配列で複数指定することもできる

正常終了時は resolve()、異常終了時は reject()、処理が完了していないときは notify() を使用して、それぞれ設定した処理を実行させます。

下の例は、処理が完了していないことを表す notify() を2回実行しています。

記述例
<label><input type="radio" name="status" checked onchange="exec(1);">正常終了</label> 
<label><input type="radio" name="status" onchange="exec(2);">異常終了</label><br>
<span id="d01"></span><br>

<script>
exec(1);
function exec(n) {
  d01.textContent = "";
  let df = $.Deferred();
  df.progress(function() { d01.textContent += "progress "; });
  df.then(function() { d01.textContent += "then1 "; },
          function() { d01.textContent += "then2 "; },
          function() { d01.textContent += "then3 "; });
  df.done(function() { d01.textContent += "done "; });
  df.fail(function() { d01.textContent += "fail "; });
  df.always(function() { d01.textContent += "always "; });

  df.notify();df.notify();
  if (n == 1)
    df.resolve();
  else
    df.reject();
}
</script>

また、上の例の jQuery の記述部分は jQuery を使用しなければ、次のように書き換えることもできます。

class Deferred {
  constructor(func) {
    this.pobj = this.promiseObject = new Promise();
    this.funcProgress = [];
    if (func != undefined) func();
    return this;
  }
  promise(obj) {
    let self = this;
    if (obj != undefined) {
      obj.done = function(func) { obj.funcDone = self.pobj._concat([], func); return obj; }
      obj.fail = function(func) { obj.funcFail = self.pobj._concat([], func); return obj; }
      this.promiseObject = obj;
    }
    return this.promiseObject;
  }
  done(args) { this.promiseObject.done(args); }
  fail(args) { this.promiseObject.fail(args); }
  then(func1, func2, func3) {
    this.promiseObject.funcDone = this.promiseObject._concat(this.promiseObject.funcDone, func1);
    this.promiseObject.funcFail = this.promiseObject._concat(this.promiseObject.funcFail, func2);
    this.funcProgress = this.promiseObject._concat(this.funcProgress, func3);
  }
  progress() { this.funcProgress = this.promiseObject._concat(this.funcProgress, arguments); }
  always() {
    this.promiseObject.funcDone = this.promiseObject._concat(this.promiseObject.funcDone, arguments);
    this.promiseObject.funcFail = this.promiseObject._concat(this.promiseObject.funcFail, arguments);
  }
  resolve() { this.promiseObject.funcDone.forEach(function(f) { f(); }); }
  reject() { this.promiseObject.funcFail.forEach(function(f) { f(); }); }
  notify() { this.funcProgress.forEach(function(f) { f(); }); }
}

exec(1);
function exec(n) {
  d01.textContent = "";
  let df = new Deferred();
  df.progress(function() { d01.textContent += "progress "; });

// 以下略(Promise は $.when のところを参照してください)

表示の順番は違っているようです。

実行例(jQuery 使用)
再実行
実行例(jQuery 未使用)
再実行

(1-3)非同期処理の実行

正常終了時(resolve)、異常終了時(reject)あるいは、処理が完了していないとき(pending)に、それぞれ設定されている関数を呼び出すために実行します。

実行したメソッドとそれによって呼び出される関数は、

resolve、resolveWithdone
reject、rejectWithfail
notify、notifyWithprogress

という関係があります。つまり、resolve を実行すると、done に設定された関数が呼ばれるわけです。

また、これらのメソッドは、処理が完了していないとき(pending)にのみ有効です。例えば、resolve の後に、notify や reject を実行しても無効です。fail や progress は呼び出されません。

なお、これらのメソッドは Deferred オブジェクトのメソッドです。

メソッド引数機能戻り値
resolve([引数[, ...]])引数:done関数に渡す引数done で指定した関数を実行する(正常終了)Deferred オブジェクト
resolveWith(thisObject[, 引数])thisObject:done関数で this として扱われる値
引数:done関数に渡す引数の配列(注)
done で指定した関数を実行する(正常終了)Deferred オブジェクト
reject([引数[, ...]])引数:fail関数に渡す引数fail で指定した関数を実行する(異常終了)Deferred オブジェクト
rejectWith(thisObject[, 引数])thisObject:fail関数で this として扱われる値
引数:fail関数に渡す引数の配列(注)
fail で指定した関数を実行する(異常終了)Deferred オブジェクト
notify([引数[, ...]])引数:progress関数に渡す引数progress で指定した関数を実行する(実行中)Deferred オブジェクト
notifyWith(thisObject[, 引数])thisObject:progress関数で this として扱われる値
引数:progress関数に渡す引数の配列(注)
progress で指定した関数を実行する(実行中)Deferred オブジェクト
注)引数は、ひとつだけでも配列として指定する

done や fail などに設定された関数内で this を使用した場合、resolve や reject など With が付かない関数を実行した場合は Window オブジェクトになります。それに対して、resolveWith や rejectWith など With が付く関数を実行した場合は、その第1引数が関数内の this の値になります。

下の例で、notify を実行した場合は、progress 内の this.mark は Window オブジェクトの mark すなわち "." となりますが、notifyWith を実行した場合は、progress 内の this.mark は notifyWith の第1引数である Emphasis オブジェクトの mark すなわち "+" となります。

なお、this については 「7.5 this」 を参考にしてください。

記述例
<label><input type="radio" name="status" checked onchange="exec(1);">正常終了</label> 
<label><input type="radio" name="status" onchange="exec(2);">異常終了</label><br>
<span id="d01"></span><br><br>
<span id="d02"></span><br><br>

<script>
class Emphasis {
  constructor() {
    this.mark = "+";
    this.lp = "《";
    this.rp = "》";
  }
}

var mark = ".";
var lp = "(";
var rp = ")";
exec(1);
function exec(n) {
  d01.textContent = d02.textContent = "";
  let df1 = $.Deferred();
  setup(df1);
  let df2 = $.Deferred();
  setup(df2);

  let symbol = new Emphasis(); 
  let int = setInterval(function() { df1.notify(d01); df2.notifyWith(symbol, [d02]); }, 1000);
  setTimeout(function() {
    if (n == 1) {
      df1.resolve(d01, "成功", new Date());           // 2つ以上の引数の例
      df2.resolveWith(symbol, [d02, "成功", new Date()]);
    }
    else {
      df1.reject(d01, ["失敗", "原因不明"]);          // 2つ以上の引数を配列で指定した例
      df2.rejectWith(symbol, [d02, ["失敗", "原因不明"]]);
    }
    window.clearInterval(int);
  }, n == 1 ? 5000 : 3000);
}

function setup(df) { // ここでの this値は、resolveからのときは Window、resolveWithからのときは Emphasisオブジェクト
  df.done(function(e, r, tm) { e.textContent += r + this.lp + tm.toLocaleString() + this.rp; });
  df.fail(function(e, p) { e.textContent += p[0] + this.lp + p[1] + this.rp; });
  df.progress(function(p) { p.textContent += this.mark; });
}
</script>

また、上の例の jQuery の記述部分は jQuery を使用しなければ、次のように書き換えることもできます。

class Deferred {
  constructor(func) {
    this.pobj = this.promiseObject = new Promise();
    this.funcProgress = [];
    if (func != undefined) func();
    return this;
  }
  promise(obj) {
    let self = this;
    if (obj != undefined) {
      obj.done = function(func) { obj.funcDone = self.pobj._concat([], func); return obj; }
      obj.fail = function(func) { obj.funcFail = self.pobj._concat([], func); return obj; }
      this.promiseObject = obj;
    }
    return this.promiseObject;
  }
  done(args) { this.promiseObject.done(args); }
  fail(args) { this.promiseObject.fail(args); }
  then(func1, func2, func3) {
    this.promiseObject.funcDone = this.promiseObject._concat(this.promiseObject.funcDone, func1);
    this.promiseObject.funcFail = this.promiseObject._concat(this.promiseObject.funcFail, func2);
    this.funcProgress = this.promiseObject._concat(this.funcProgress, func3);
  }
  progress() { this.funcProgress = this.promiseObject._concat(this.funcProgress, arguments); }
  always() {
    this.promiseObject.funcDone = this.promiseObject._concat(this.promiseObject.funcDone, arguments);
    this.promiseObject.funcFail = this.promiseObject._concat(this.promiseObject.funcFail, arguments);
  }
  resolve() {
    let args = arguments;
    this.promiseObject.funcDone.forEach(function(f) { f.apply(this, args); });
  }
  resolveWith(thisObject, args) {
    this.promiseObject.funcDone.forEach(function(f) { f.apply(thisObject, args); });
  }
  reject() {
    let args = arguments;
    this.promiseObject.funcFail.forEach(function(f) { f.apply(this, args); });
  }
  rejectWith(thisObject, args) {
    this.promiseObject.funcFail.forEach(function(f) { f.apply(thisObject, args); });
  }
  notify() {
    let args = arguments;
    this.funcProgress.forEach(function(f) { f.apply(this, args); });
  }
  notifyWith(thisObject, args) {
    this.funcProgress.forEach(function(f) { f.apply(thisObject, args); });
  }
  // 未使用メソッド略(「(1-2)非同期処理の設定」のところを参照してください)
}
class Emphasis {
  constructor() {
    this.mark = "+";
    this.lp = "《";
    this.rp = "》";
  }
}

var mark = ".";
var lp = "(";
var rp = ")";
exec(1);
function exec(n) {
  d01.textContent = d02.textContent = "";
  let df1 = new Deferred();
  setup(df1);
  let df2 = new Deferred();
  setup(df2);

// 以下略(Promise は $.when のところを参照してください)

実行例(jQuery 使用)
再実行
実行例(jQuery 未使用)
再実行

(1-4)非同期処理の状態

正常終了(resolve)、異常終了(reject)あるいは、処理が完了していない(pending)のどの状態にあるのかを調べます。

なお、このメソッドは Deferred オブジェクトのメソッドです。

メソッド引数機能戻り値
state()なしDeferredオブジェクトの現在の状態を調べる"pending"  処理が完了していない
"resolved" 正常終了している
"rejected" 異常終了している

記述例
<label><input type="radio" name="status" checked onchange="exec(1);">正常終了</label> 
<label><input type="radio" name="status" onchange="exec(2);">異常終了</label><br>
<span id="d01"></span><br><br>

<script>
exec(1);
function exec(n) {
  d01.textContent = "";
  let df = $.Deferred();
  setup(df);

  let int = setInterval(function() { df.notify(d01); }, 1000);
  setTimeout(function() {
    if (n == 1)
      df.resolve(d01);
    else
      df.reject(d01);
    window.clearInterval(int);
  }, n == 1 ? 5000 : 3000);
}

function setup(df) {
  df.done(function(e) { e.textContent += df.state() + " "; });
  df.fail(function(e) { e.textContent += df.state() + " "; });
  df.progress(function(e) { e.textContent += df.state() + " "; });
}
</script>

また、上の例の jQuery の記述部分は jQuery を使用しなければ、次のように書き換えることもできます。

class Deferred {
  constructor(func) {
    this.pobj = this.promiseObject = new Promise();
    this.funcProgress = [];
    this._state = "pending";
    if (func != undefined) func();
    return this;
  }
  promise(obj) {
    let self = this;
    if (obj != undefined) {
      obj.done = function(func) { obj.funcDone = self.pobj._concat([], func); return obj; }
      obj.fail = function(func) { obj.funcFail = self.pobj._concat([], func); return obj; }
      this.promiseObject = obj;
    }
    return this.promiseObject;
  }
  done(args) { this.promiseObject.done(args); }
  fail(args) { this.promiseObject.fail(args); }
  progress() { this.funcProgress = this.promiseObject._concat(this.funcProgress, arguments); }
  resolve() {
    this._state = "resolved";        // resolveWith にも必要
    let args = arguments;
    this.promiseObject.funcDone.forEach(function(f) { f.apply(this, args); });
  }
  reject() {
    this._state = "rejected";        // rejectWith にも必要
    let args = arguments;
    this.promiseObject.funcFail.forEach(function(f) { f.apply(this, args); });
  }
  notify() {
    let args = arguments;
    this.funcProgress.forEach(function(f) { f.apply(this, args); });
  }
  state() { return this._state; }

  // 未使用メソッド略(「(1-2)非同期処理の設定」「(1-3)非同期処理の実行」のところを参照してください)}

exec(1);
function exec(n) {
  d01.textContent = "";
  let df = new Deferred();
  setup(df);

// 以下略(Promise は $.when のところを参照してください)

実行例(jQuery 使用)
再実行
実行例(jQuery 未使用)
再実行

13.3.12  演出効果

演出効果として、スタイルシートの値を変更して、アニメーションを行います。

ただし、指定できる属性は left、width、opacity など数値を指定するものに限られます。したがって、color や display のような文字列を指定する属性は利用できません(プラグインを別途組み込んだり、コールバック関数を使用すれば利用できる属性もあります)。

(1)設定

プロパティ
$.fx.offtrue:アニメーションさせない、false:アニメーションさせる

$.fx.off はアニメーションの演出効果を使用するかどうかを設定します。

下の例では、アニメーションのチェックを付けると $.fx.off が false になり、アニメーションします。

記述例
<style>
div {
  width: 30px;
  background-color: aquamarine;
}
</style>

<input type="checkbox" checked onchange="sw(this);">アニメーション<br>
<div id="d01" onmouseenter="expand();"><br></div>

<script>
$("#d01").animate({ width: 30 }, 1000);
function expand() {
  $("#d01").css({ width: "30px" });
  $("#d01").animate({ width: 300 }, 1000);
}
function sw(me) {
  $.fx.off = !me.checked;
  $("#d01").css({ width: "30px" });
}
</script>

また、上の例の jQuery の記述部分は jQuery を使用しなければ、次のように書き換えることもできます。

jQuery を使用しない場合は、一度行ったアニメーションをもう一度行うことができませんので、一度別のアニメーション(compact)にして、再度 expand にしています。

アニメーションについては、「9 アニメーション」を参照してください。

<style>
@keyframes expand {
  0% {width: 30px;}
  100% {width: 300px;}
}
@keyframes contract {
  0% {width: 300px;}
  100% {width: 30px;}
}
div#d01 {
  width: 30px;
  background-color: aquamarine;
  animation-fill-mode:forwards;
  animation-timing-function:linear;
  animation-duration:0s;
}
</style>

<input type="checkbox" checked onchange="sw(this);">アニメーション<br>
<div id="d01" onanimationend="enable();"><br></div>

<script>
var fxOff = false;
enable();
async function expand() {
  d01.style.animationName = "contract";
  d01.style.animationDuration = "0s";
  await sleep(10);     // 少しディレイしないとアニメーションが変わらない(?)
  disable();            // アニメーション中はイベントを無効にする
  d01.style.animationDuration = fxOff ? "0s" : "1s";
  d01.style.animationName = "expand";
}
function sw(me) {
  fxOff = !me.checked;
  d01.style.animationName = "contract";
  d01.style.animationDuration = "0s";
  enable();
}
function enable() {
  d01.addEventListener("mouseenter", expand, false);
}
function disable() {
  d01.removeEventListener("mouseenter", expand, false);
}
function sleep(msec) {
  return new Promise(function(resolve) {
    setTimeout(resolve, msec);
  });
}
</script>
実行例(jQuery 使用)
実行例(jQuery 未使用)

(2)実行

(2-1)アニメーションの表現

メソッド引数機能戻り値
animate(属性[,時間]
    [,イージング][,関数])
属性:CSS属性名と値からなるオブジェクト
  {
    属性名: 値,
    :
  }
時間:アニメーション再生時間(ミリ秒)(規定値:400)(注1)
イージング:変化のタイミング(規定値:swing)(注2)
関数:アニメーション終了時の処理
CSSの値を指定して、
アニメーションを表現する
jQuery オブジェクト
animate(属性,オプション)属性:CSS属性名と値からなるオブジェクト
  {
    属性名: 値,
    :
  }
オプション:次のキーを持つオブジェクト(注3)
CSSの値を指定して、
アニメーションを表現する
jQuery オブジェクト
注1)ミリ秒以外に次のキーワードも指定できる
キーワード意味
fast200 ミリ秒
normal400 ミリ秒
slow600 ミリ秒
注2)次のキーワードが指定できる
キーワード意味
linear一定速度
swing徐々に加速し、徐々に減速

注3)次のキーワードが指定できる
キーワード意味
durationアニメーション再生時間"slow"、"normal"、"fast"、もしくは、ミリ秒(規定値:"normal")
easingイージングの種類"linear"、"swing"、もしくは関数(規定値:"swing")
function(x, t, 0, 1, d)
 x: アニメーションの進捗率(0 ~ 1)
 t: 経過時間(ミリ秒)
 d: アニメーション実行のトータル時間(ミリ秒)
 戻り値: 変化率(start と end 間の位置)(0 ~ 1)
queueアニメーション実行true:即実行、false:キューに保存(規定値:true)
specialEasing属性名ごとのイージングの種類属性名とイージングの種類からなるオブジェクト(規定値:"swing")
{
 属性名:イージングの種類,
 :
}
startアニメーション開始時の処理関数
function(Promise animation)
 animation: アニメーション情報
  elem: 要素情報
  props: 属性情報の配列
  startTime:開始時刻
  tweens:要素とその属性などの配列   など
stepアニメーション実行中のフレーム毎、プロパティ毎に呼び出される処理関数
function(Number now, Tween tween)
 now: 現在の属性値
 tween: { (アニメーションしている要素とその属性)
  elem: 要素名
  prop: 属性名
 }
progressアニメーション実行中のフレーム毎に一度だけ呼び出される処理関数
function(Promise animation, Number progress, Number remainingMs)
 animation: アニメーション情報
 progress: アニメーションの進行状況(0~1)
 remainingMs: アニメーションの残りのミリ秒(?)
completeアニメーション終了時の処理関数
function()
doneアニメーションが正常終了したときの処理関数
function(Promise animation, Boolean jumpedToEnd)
 animation: アニメーション情報
 jumpedToEnd: アニメーションの終了状況
         undefined:自然終了した
         true:finish()で目的値にして終了した
failアニメーションが異常終了したときの処理関数
function(Promise animation, Boolean jumpedToEnd)
 animation: アニメーション情報
 jumpedToEnd: アニメーションの終了状況
         undefined:stop()で目的値にせず終了した(注)仕様では false(?)
alwaysアニメーションが正常終了か異常終了か関係なく終了したときの処理関数
function(Promise animation, Boolean jumpedToEnd)
 animation: アニメーション情報
 jumpedToEnd: アニメーションの終了状況
         undefined:自然終了した
         true:finish()で目的値にして終了した
         undefined:stop()で目的値にせず終了した(注)仕様では false(?)
注)目的値:属性で指定した値(アニメーションが自然終了したときになるべき値)

○ animate(属性[,時間][,イージング][,関数])

記述例
<style>
div {
  margin: 3px;
  width: 10px;
  height: 15px;
  font-size: 9pt;
  background-color: aquamarine;
}
</style>
<div id="d01">fast</div>
<!-- 以下略 -->

<script>
$("#d01").animate({"width":300}, "fast");
$("#d02").animate({"width":300}, "normal");
$("#d03").animate({"width":300}, "slow");
$("#d04").animate({"width":300}, 1000);
$("#d11").animate({"width":300}, 3000, "linear");
$("#d12").animate({"width":300}, 3000, "swing");
</script>

また、上の例の jQuery の記述部分は jQuery を使用しなければ、次のように書き換えることもできます。

アニメーションについては、「9 アニメーション」を参照してください。

<style>
@keyframes anime {
  from {width: 0px;}
  to {width: 300px;}
}
div {
  margin: 3px;
  width: 10px;
  height: 15px;
  font-size: 9pt;
  background-color: aquamarine;
}
</style>

<script>
d01.style.animation = "anime 200ms forwards";
d02.style.animation = "anime 400ms forwards";
d03.style.animation = "anime 600ms forwards";
d04.style.animation = "anime 1s forwards";
d11.style.animation = "anime 3s forwards linear";
d12.style.animation = "anime 3s forwards ease-in-out";
</script>
実行例(jQuery 使用)
再実行
実行例(jQuery 未使用)
再実行

○ animate(属性,オプション)

先の animate をより詳細に設定できるようにしたものです。引数はすべてオブジェクトとして一つにまとめてありますし、設定できる項目も取得できる情報も大幅に増えています。

ただし、次の例では、すべての項目は設定できていませんし、得られた情報も一部のみを表示しています。

記述例
<div id="a01"></div>
<button class="switch" onclick="stop();">stop</button> <button class="switch" onclick="finish();">finish</button><br>

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

<script>
$("#a01").animate({width:250, height:100}, 
  {
    duration: 5000,
    specialEasing: {
      width: "swing",
      height: "linear"
    },
    start: function(animation) {var dt = new Date(animation.startTime); d01.textContent = dt.toLocaleString();},
    step: function(now, tween) {
            if (tween.prop == "width") d11.textContent = now + "px";
            else if (tween.prop == "height") d12.textContent = now + "px";
          },
    progress: function(animation, progress, remainingMs) {
                d13.textContent = remainingMs + "mS";
              },
    complete: function() {d21.textContent = "finish";},
    done: function(animation, jumpedToEnd) {d22.textContent = jumpedToEnd==undefined?"undefined":jumpedToEnd;},
    fail: function(animation, jumpedToEnd) {d23.textContent = jumpedToEnd==undefined?"undefined":jumpedToEnd;},
    always: function(animation, jumpedToEnd) {d24.textContent = jumpedToEnd==undefined?"undefined":jumpedToEnd;}
  });
function stop() {
  $("#a01").stop();
}
function finish() {
  $("#a01").finish();
}
</script>

また、上の例の jQuery の記述部分は jQuery を使用しなければ、次のように書き換えることもできます。

しかし、javascript とスタイルシートだけでは、step のようにアニメーション途中で処理を差し挟むができません(?)(繰返しごとにはできます)。この例では、アニメーション途中でも width や height を書き込むために、タイマーを設定して行っています。

また、属性ごと異なる easing を設定することもできませんので、同じ設定(ease-in-out)にしています。

<style>
@keyframes expand {
    0% {width: 0px; height: 0px;}
  100% {width: 250px; height: 100px;}
}
@keyframes expandx {
    0% {width: 250px; height: 100px;}
  100% {width: 250px; height: 100px;}
}
div#a01 {
  animation-name:expand;
  animation-duration:5s;
  animation-timing-function:ease-in-out;
  animation-fill-mode:forwards;
}
</style>

<script>
a01.addEventListener("animationstart", start, false);
a01.addEventListener("animationend", complete, false);

var timer = null;
var endTime = 0;
function start() {
  let dt = new Date();
  d01.textContent = dt.toLocaleString();
  timer = window.setInterval(step, 5000/100);
  endTime = dt.getTime() + 5000 ;
}

function step() {
  d11.textContent = a01.clientWidth + "px";
  d12.textContent = a01.clientHeight + "px";
  d13.textContent = (endTime - (new Date()).getTime()) + "mS";
}
function complete() {
  d21.textContent = "finish";
  d22.textContent = undefined;
  d24.textContent = undefined;
  d13.textContent = "0mS";
  window.clearInterval(timer);
}
function stop() {
  d23.textContent = undefined;
  d24.textContent = undefined;
  a01.style.animationPlayState = "paused";
  window.clearInterval(timer);
}
function finish() {
  a01.style.animationPlayState = "paused";
  a01.style.animationName = "expandx";
  window.clearInterval(timer);
  d11.textContent = a01.clientWidth + "px";
  d12.textContent = a01.clientHeight + "px";
  d13.textContent = "0mS";
  d21.textContent = "finish";
  d22.textContent = true;
  d24.textContent = true;
  a01.removeEventListener("animationstart", start);
}
</script>
実行例(jQuery 使用)
再実行
実行例(jQuery 未使用)
再実行

背景色を変化させたり、イメージの回転させたりするには、background-color や transform という本来利用できない属性を変更する必要があります。背景色の変化の例では width の変化の途中(step)で、イメージの回転の例では z-index を変化させ、その途中で呼ばれれる関数で rgb値や rotate の角度を変更するようにして、アニメーションさせています。

記述例
<div id="d01">begin</div>
<img id="d02" src="figures/effect01.png" height="150" width="150">

<script>
$("#d01").animate({width: 250}, 
                  {
                    duration: 3000,      // 3秒かけてアニメーション
                    easing: "swing",
                    step: function(now) {
                            $(this).text(parseInt(now * 100 / 250) + "%");
                            let c = parseInt(now * 255 / 250);
                            $(this).css("background-color", "rgb(" + (255 - c) + ", " + c + ", 0)"); 
                          },
                    complete: function() {$(this).text("finish");}
                  });
$("#d02").animate({zIndex: 1}, 
                  {
                    duration: 3000,
                    easing: "linear",
                    step: function(now){  // stepは、アニメーションが進むたびに呼ばれる
                      // now に現在の z-index の値(0から1に変化しているところ)が渡してもらえる
                      $(this).css({transform:"rotate(" + (-now * 1080) + "deg)"});
                    },
                    complete: function(){    // 終わったら、次のために、元に戻しておく
                      $("#d02").css("zIndex", 0);
                    }
                  });
</script>

また、上の例の jQuery の記述部分は jQuery を使用しなければ、次のように書き換えることもできます。

変化する背景色や回転するイメージはスタイルシートの設定のみで実現できます。

しかし、javascript とスタイルシートだけでは、step のようにアニメーション途中で処理を差し挟むができません(?)(繰返しごとにはできます)。この例では、アニメーション途中でもパーセンテージを書き込むために、タイマーを設定して行っています。

<style>
@keyframes expand {
  0% {width: 0px; background-color: red;}
  100% {width: 250px; background-color: lime;}
}
@keyframes spin {
  0% {transform: rotate(0deg);}
  100% {transform: rotate(-1080deg);}
}
div#d01 {
  margin: 3px;
  width: 0px;
  font-size: 12pt;
  background-color: red;
  overflow-x: visible;
  animation-name:expand;
  animation-fill-mode:forwards;
  animation-timing-function:ease-in-out;
  animation-duration:3s;
  animation-fill-mode:forwards;
}
img#d02 {
  animation-name:spin;
  animation-fill-mode:forwards;
  animation-timing-function:linear;
  animation-duration:3s;
}
</style>

<script>
var timer = null;
d01.addEventListener("animationstart", function() {
  timer = window.setInterval(               // パーセンテージ表示
            function() { d01.textContent = parseInt(d01.clientWidth * 100 / 250) + "%"; }, 3000/100);
}, false);
d01.addEventListener("animationend", function() {
  window.clearInterval(timer);
}, false);
</script>
実行例(jQuery 使用)
再実行
実行例(jQuery 未使用)
再実行

◇ easing について

標準では、"linear"、"swing" しかありませんが、関数も指定できるので自由に作成することができます。

function(x, t, 0, 1, d)

easing に使用される変化率を返す。

引数 x:アニメーションの進捗率(0 ~ 1)

引数 t:経過時間(ミリ秒)

引数 d:アニメーション実行のトータル時間(ミリ秒)

戻り値:変化率(start(0) と end(1) 間の位置)(0 ~ 1 の範囲外でも可)

関数の戻り値として、進捗率に対してどのような値をとるかを返します。

例えば、進捗率と同じ値ならば、一定速度で増加する linear の変化になります。

また、戻り値は通常 0(開始時の値)から 1(終了時の値)の範囲ですが、負の値や1より大きい値でも構いません(special2 がその例です)。

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

<script>
var duration = 2000;

function start() {
  useEffect($("#d01"), "linear");
  useEffect($("#d02"), "special1");      // 作成した easing 関数の名前
  useEffect($("#d03"), "special2");
};

function useEffect(element, easing) {
  element.animate({ width: 270 }, duration, easing)
         .animate({ width: 90 }, duration, easing);
}

jQuery.easing.special1 = function(x, t, b, c, d) {
  return x + Math.sin(4 * x * Math.PI) / 4;
}
jQuery.easing.special2 = function(x, t, b, c, d) {
  return x - Math.sin(x * Math.PI * 2) / 2;
}
</script>

easing の名前をクリックしてもアニメーションが実行されますが、そのときの背景に表示されるグレイの帯は linear です。

実行例(jQuery 使用)

また、「easing」を拡張するプラグイン jquery.easing.js を利用すると、さらに多くの easing を表現することができます。

実行例(jQuery 使用)

(2-2)アニメーションの停止・遅延

メソッド引数機能戻り値
stop([クリア[,ゴール]])クリア:次以降のアニメーションを行わない(true)(規定値:false)
ゴール:目的値にして終了する(true)(規定値:false)
実行中の animate を停止するjQuery オブジェクト
stop(キュー[,クリア[,ゴール]])キュー:停止するキュー名(指定しないとすべて)
クリア:次以降のアニメーションを行わない(true)(規定値:false)
ゴール:目的値にして終了する(true)(規定値:false)
実行中の animate を停止するjQuery オブジェクト
finish([キュー])キュー:停止するキュー名(指定しないとすべて)目的値にして、
アニメーションを終了する
jQuery オブジェクト
delay(期間[,キュー])期間:停止する時間(mS)
キュー:停止するキュー名(指定しないとすべて)
アニメーションを
一時的に停止する
jQuery オブジェクト
注)目的値:animate の属性で指定した値(アニメーションが自然終了したときになるべき値)

stop の引数による動作の違いは次のようになります。なお、complete、done、fail に定義された関数が呼ばれる場合は ○、呼ばれない場合は × で表しています。

メソッド動作completedonefail
stop(false, false)実行中の animate を停止し、次の animate を、現状から開始する××
stop(false, true)実行中の animate を停止し、次の animate を、停止した animate の目的値から開始する×
stop(true, false)すべての animate を、現状の表示で完全に停止する××
stop(true, true)すべての animate を、実行中の animate の目的値にし完全に停止する×
記述例
<div id="d01" style="width:0px;height:0px;background-color:red;"></div>
<div class="switch" onclick="$('#d01').stop(false, false);">stop(false, false)</div>
<div class="switch" onclick="$('#d01').stop(false, true);">stop(false, true)</div>
<div class="switch" onclick="$('#d01').stop(true, false);">stop(true, false)</div>
<div class="switch" onclick="$('#d01').stop(true, true);">stop(true, true)</div>
<div class="switch" onclick="$('#d01').finish();">finish()</div>
<script>
$("#d01").animate({width:100, height:100, top:0, left:0},
                  {
                    duration:3000,
                    complete:function() { $(this).css("background-color", "yellow");},
                    done:function() { $(this).text("done"); },
                    fail:function() { $(this).text("fail"); }
                  })
         .delay(1000)
         .animate({width:0, height:0, top:50, left:50},
                  {
                    duration:3000,
                    complete:function() { $(this).css("background-color", "blue");},
                    done:function() { $(this).text("done"); },
                    fail:function() { $(this).text("fail"); }
                  })
         .delay(0)
         .animate({width:100, height:100, top:0, left:0},
                  {
                    duration:3000,
                    done:function() { $(this).text("done"); },
                    fail:function() { $(this).text("fail"); }
                  });
</script>

また、上の例の jQuery の記述部分は jQuery を使用しなければ、次のように書き換えることもできます(とても長い)。

<style>
@keyframes animate1 {
  0% {width:0px; height:0px; top:50px; left:50px;}
  100% {width:100px;  height:100px; top:0px; left:0px;}
}
@keyframes animate2 {
  0% {width:100px;  height:100px; top:0px; left:0px;}
  100% {width:0px; height:0px; top:50px; left:50px;}
}
@keyframes animate3 {
  0% {width:0px; height:0px; top:50px; left:50px;}
  100% {width:100px;  height:100px; top:0px; left:0px;}
}
</style>

<div id="d01" style="width:0px;height:0px;background-color:red;"></div>
<div class="switch" onclick="stop(d01, false, false);">stop(false, false)</div>
<div class="switch" onclick="stop(d01, false, true);">stop(false, true)</div>
<div class="switch" onclick="stop(d01, true, false);">stop(true, false)</div>
<div class="switch" onclick="stop(d01, true, true);">stop(true, true)</div>
<div class="switch" onclick="finish(d01);">finish()</div>

<script>
var animList = [
  {
     name:"animate1",
     animation:"animate1 3s alternate both",
     complete:function() { this.style.backgroundColor = "yellow"; },
     done:function() { this.textContent = "done"; },
     fail:function() { this.textContent = "fail"; }
  },
  {
     name:"animate2",
     animation:"animate2 3s 1s alternate both",
     complete:function() { this.style.backgroundColor = "blue"; },
     done:function() { this.textContent = "done"; },
     fail:function() { this.textContent = "fail"; }
  },
  {
     name:"animate3",
     animation:"animate3 3s alternate both",
     done:function() { this.textContent = "done"; },
     fail:function() { this.textContent = "fail"; }
  }
];


class Animation {
  constructor(list) {
    this.animNo = 0;
    this.animList = list == undefined ? [] : list;
    this.animCount = this.animList.length;
  }
  play(elem) {
    let curr = this.current();
    if (curr.done != undefined) curr.done.apply(elem);
    if (curr.complete != undefined) curr.complete.apply(elem);
    let nx = this.next()
    if (nx != null) elem.style.animation = nx.animation;    // 次があれば次のアニメーション
  }
  set(anim) {
    this.animList = anim;
  }
  first() {
    if (this.animCount == 0) return null;
    return this.animList[0];
  }
  current() {
    if (this.animCount == 0) return null;
    return this.animList[this.animNo];
  }
  next() {
    if (++this.animNo >= this.animList.length) return null;
    return this.animList[this.animNo];
  }
  last() {
    if (this.animCount == 0) return null;
    return this.animList[this.animCount - 1];
  }
  isLast() {
    return this.animNo >= this.animList.length - 1;
  }
  getKeyFrame(css, name, key) {
    let rules = css.cssRules;
    let n = rules.length;
    for (let i = 0 ; i < n ; i++) {
      if (rules[i].name == name)
        return this._getKeyFrame(rules[i], key);
    }
    return "";
  }
  _getKeyFrame(rule, key) {
    if (rule.cssRules == undefined)
    return "";
    let n = rule.cssRules.length;
    for (let i = 0 ; i < n ; i++) {
      if (rule.cssRules[i].keyText == key)
        return rule.cssRules[i].style.cssText;
    }
    return "";
  }
  setKeyFrame(css, name, key, ss) {
    let rules = css.cssRules;
    let n = rules.length;
    for (let i = 0 ; i < n ; i++) {
      if (rules[i].name == name)
        this._setKeyFrame(rules[i], key, ss);
    }
  }
  _setKeyFrame(rule, key, ss) {
    let n = rule.cssRules.length;
    for (var i = 0 ; i < rule.cssRules.length ; i++) {
      if (rule.cssRules[i].keyText == key) {
        rule.cssRules[i].style.cssText = ss;
        break;
      }
    }
  }
}

var styleSheet = document.styleSheets[0];      // 複数定義されているスタイルシートの1番目
var animation = new Animation(animList);
d01.style.animation = animation.first().animation;
d01.addEventListener("animationend", nextAnimation(d01), false);

function nextAnimation(elem) {
  return function() {
    animation.play(elem);
  }
}

function stop(elem, clear, goal) {
  var curr = animation.current();
  if (curr == null) return;
  elem.style.animationPlayState = "paused";      // アニメーションを停止する
  if (clear) {
    if(goal) {
      // true, true(実行中のアニメーションの目的値にし完全に停止する)
      elem.style.cssText += animation.getKeyFrame(styleSheet, curr.name, "100%");
      elem.style.animation = "";
      if (curr.done != undefined) curr.done.apply(elem);
      if (curr.complete != undefined) curr.complete.apply(elem);
    }
    else {
      // true, false(現状の表示で完全に停止する)
      if (curr.fail != undefined) curr.fail.apply(elem);
    }
  }
  else {
    if(goal) {
      // false, true(実行中のアニメーションを停止し、次のアニメーションを、停止したアニメーションの目的値から開始する)
      if (animation.isLast()) {
        // 最後のアニメーションのとき
        elem.style.cssText += animation.getKeyFrame(styleSheet, curr.name, "100%");    // 目的値にして終了
        elem.style.animation = "";
      }
      else {
        // 最後のアニメーションでないとき
        elem.style.animation = animation.next().animation;
        elem.style.animationPlayState = "running";               // 次のアニメーションを継続する
      }
      if (curr.done != undefined) curr.done.apply(elem);
      if (curr.complete != undefined) curr.complete.apply(elem);
    }
    else {
      // false, false(実行中のアニメーションを停止し、次のアニメーションを現状から開始する)
      if (curr.fail != undefined) curr.fail.apply(elem);
      let w = elem.clientWidth;
      let h = elem.clientHeight;
      let t = elem.offsetTop;
      let l = elem.offsetLeft;
      let ss = "width:" + w + "px; height:" + h + "px; top:" + t + "px; left:" + l + "px;";
      let nx = animation.next();
      if (nx != null) {
        animation.setKeyFrame(styleSheet, nx.name, "0%", ss);
        elem.style.animation = nx.animation;
        elem.style.animationPlayState = "running";
      }
    }
  }
}

function finish(elem) {
  animation.first();
  do {
    curr = animation.current();
    if (curr.done != undefined) curr.done.apply(elem);
    if (curr.complete != undefined) curr.complete.apply(elem);
  } while(animation.next() != null);
  elem.style.cssText += animation.getKeyFrame(styleSheet, curr.name, "100%");    // 最後のアニメーションの目的値にして終了
  elem.style.animation = "";
}
</script>

実行例(jQuery 使用)
再実行
実行例(jQuery 未使用)
再実行

(2-3)アニメーションの表示

メソッド引数機能戻り値
show([時間][,イージング][,関数])時間:表示に掛ける時間(ミリ秒)(注1)(規定値:0)
イージング:変化のタイミング(注2)(規定値:swing)
関数:表示後の処理
要素を表示するjQuery オブジェクト
show(オプション)オプション:次のキーを持つオブジェクト(注3)要素を表示するjQuery オブジェクト
hide([時間][,イージング][,関数])時間:非表示に掛ける時間(ミリ秒)(注1)(規定値:400)
イージング:変化のタイミング(注2)(規定値:swing)
関数:表示後の処理
要素を非表示にするjQuery オブジェクト
hide(オプション)オプション:次のキーを持つオブジェクト(注3)要素を非表示にするjQuery オブジェクト
toggle([時間][,イージング][,関数])時間:表示・非表示に掛ける時間(ミリ秒)(注1)(規定値:0)
イージング:変化のタイミング(注2)(規定値:swing)
関数:表示・非表示後の処理
要素の表示・非表示を切り替えるjQuery オブジェクト
toggle(オプション)オプション:次のキーを持つオブジェクト(注3)要素の表示・非表示を切り替えるjQuery オブジェクト
toggle(スイッチ)スイッチ:表示(true)、非表示(false)要素の表示・非表示を切り替えるjQuery オブジェクト
注)目的値:animate の属性で指定した値(アニメーションが自然終了したときになるべき値)
注1)ミリ秒以外に次のキーワードも指定できる
キーワード意味
fast200 ミリ秒
normal400 ミリ秒
slow600 ミリ秒
注2)次のキーワードが指定できる
キーワード意味
linear一定速度
swing徐々に加速し、徐々に減速

注3)次のキーワードが指定できる
キーワード意味
durationアニメーション再生時間"slow"、"normal"、"fast"、もしくは、ミリ秒(規定値:"normal")
easingイージングの種類"linear"、"swing"、もしくは関数(規定値:"swing")
function(x, t, 0, 1, d)
 x: アニメーションの進捗率(0 ~ 1)
 t: 経過時間(ミリ秒)
 d: アニメーション実行のトータル時間(ミリ秒)
 戻り値: 変化率(start と end 間の位置)(0 ~ 1)
queueアニメーション実行true:即実行、false:キューに保存(規定値:true)
specialEasing属性名ごとのイージングの種類属性名とイージングの種類からなるオブジェクト(規定値:"swing")
{
 属性名:イージングの種類,
 :
}
startアニメーション開始時の処理関数
function(Promise animation)
 animation: アニメーション情報
  elem: 要素情報
  props: 属性情報の配列
  startTime:開始時刻
  tweens:要素とその属性などの配列   など
stepアニメーション実行中のフレーム毎、プロパティ毎に呼び出される処理関数
function(Number now, Tween tween)
 now: 現在の属性値
 tween: { (アニメーションしている要素とその属性)
  elem: 要素名
  prop: 属性名
 }
progressアニメーション実行中のフレーム毎に一度だけ呼び出される処理関数
function(Promise animation, Number progress, Number remainingMs)
 animation: アニメーション情報
 progress: アニメーションの進行状況(0~1)
 remainingMs: アニメーションの残りのミリ秒(?)
completeアニメーション終了時の処理関数
function()
doneアニメーションが正常終了したときの処理関数
function(Promise animation, Boolean jumpedToEnd)
 animation: アニメーション情報
 jumpedToEnd: アニメーションの終了状況
         undefined:自然終了した
         true:finish()で目的値にして終了した
failアニメーションが異常終了したときの処理関数
function(Promise animation, Boolean jumpedToEnd)
 animation: アニメーション情報
 jumpedToEnd: アニメーションの終了状況
         undefined:stop()で目的値にせず終了した(注)仕様では false(?)
alwaysアニメーションが正常終了か異常終了か関係なく終了したときの処理関数
function(Promise animation, Boolean jumpedToEnd)
 animation: アニメーション情報
 jumpedToEnd: アニメーションの終了状況
         undefined:自然終了した
         true:finish()で目的値にして終了した
         undefined:stop()で目的値にせず終了した(注)仕様では false(?)
注)目的値:属性で指定した値(アニメーションが自然終了したときになるべき値)

○ show(属性[,時間][,イージング][,関数])、hide(属性[,時間][,イージング][,関数])、   toggle(属性[,時間][,イージング][,関数])

show で表示し、hide で非表示になります。ただし、表示のときは次第に拡大し濃くなっていき、非表示のときは次第に縮小し薄くなっていきます。

また、toggle は、表示されていない場合は show を、表示されている場合は hide を実行します。

ただし、次の例では、show と hide について記述しています。また、すべての項目は設定できていませんし、得られた情報も一部のみを表示しています。

記述例
<span id="title"></span>
<div id="d01">(引数なし)</div>
<!-- 途中略 -->

<img id="d21" src="figures/bear.png">
<script>
hide();

function show() {
  $("#title").text("show");
  $("#d01").show();
  $("#d02").show("fast");
  $("#d03").show("normal");
  $("#d04").show("slow");
  $("#d05").show(1000);
  $("#d11").show(3000, "linear");
  $("#d12").show(3000, "swing");
  $("#d21").show(3000, "linear");
}
function hide() {
  $("#title").text("hide");
  $("#d01").hide();
  $("#d02").hide("fast");
  $("#d03").hide("normal");
  $("#d04").hide("slow");
  $("#d05").hide(1000);
  $("#d11").hide(3000, "linear");
  $("#d12").hide(3000, "swing");
  $("#d21").hide(3000, "linear", show);   // 終了したら show を呼び出す
}
</script>

また、上の例の jQuery の記述部分は jQuery を使用しなければ、次のように書き換えることもできます。

<style>
@keyframes show {
  from {width: 0px; height: 0px; opacity:0;}
  to {width: 80px; height: 15px; opacity:1;}
}
@keyframes showImg {
  from {width: 0px; height: 0px; opacity:0;}
  to {width: 74px; height: 74px; opacity:1;}
}
@keyframes hide {
  from {width: 80px; height: 15px; opacity:1;}
  to {width: 0px; height: 0px; opacity:0;}
}
@keyframes hideImg {
  from {width: 74px; height: 74px; opacity:0;}
  to {width: 0px; height: 0px; opacity:1;}
}
</style>

<script>
d21.addEventListener("animationend", show, false);   // 終了したら show を呼び出す
var e = [].slice.call(document.querySelectorAll("div[id]"));
e.forEach(function(e, i) { e.addEventListener("animationend", none, false); });
hide();

function show() {
  d21.removeEventListener("animationend", show, false);
  e.forEach(function(e, i) { e.removeEventListener("animationend", none, false); e.style.display = "block"; });
  title.textContent = "show";
  d01.style.animation = "show forwards";
  d02.style.animation = "show 200ms forwards";
  d03.style.animation = "show 400ms forwards";
  d04.style.animation = "show 600ms forwards";
  d05.style.animation = "show 1s forwards";
  d11.style.animation = "show 3s forwards linear";
  d12.style.animation = "show 3s forwards ease-in-out";
  d21.style.animation = "showImg 3s forwards linear";
}
function hide() {
  title.textContent = "hide";
  d01.style.animation = "hide forwards";
  d02.style.animation = "hide 200ms forwards";
  d03.style.animation = "hide 400ms forwards";
  d04.style.animation = "hide 600ms forwards";
  d05.style.animation = "hide 1s forwards";
  d11.style.animation = "hide 3s forwards linear";
  d12.style.animation = "hide 3s forwards ease-in-out";
  d21.style.animation = "hideImg 3s forwards linear";
}
function none() { this.style.display = "none"; }
</script>
実行例(jQuery 使用)
再実行
実行例(jQuery 未使用)
再実行

○ toggle(オプション)、   show(オプション)、hide(オプション)

先のメソッドをより詳細に設定できるようにしたものです。引数はすべてオブジェクトとして一つにまとめてありますし、設定できる項目も取得できる情報も大幅に増えています。

ただし、次の例では、toggle について記述しています。また、すべての項目は設定できていませんし、得られた情報も一部のみを表示しています。

記述例
<section onclick="toggle();">
  <div id="a01">click(再実行)</div>
</section>
<button class="switch" onclick="finish();">finish</button><br>

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

<script>
toggle();
function toggle() {
  clear();
  $("#a01").animate({width:250, height:100}, 
    {
      duration: 5000,
      specialEasing: {
        width: "swing",
        height: "linear"
      },
      start: function(animation) {var dt = new Date(animation.startTime); d01.textContent = dt.toLocaleString();},
      step: function(now, tween) {
              if (tween.prop == "width") d11.textContent = now + "px";
              else if (tween.prop == "height") d12.textContent = now + "px";
            },
      progress: function(animation, progress, remainingMs) { d13.textContent = remainingMs + "mS"; },
      complete: function() {d21.textContent = "finish";},
      done: function(animation, jumpedToEnd) {d22.textContent = jumpedToEnd==undefined?"undefined":jumpedToEnd;},
      fail: function(animation, jumpedToEnd) {d23.textContent = jumpedToEnd==undefined?"undefined":jumpedToEnd;},
      always: function(animation, jumpedToEnd) {d24.textContent = jumpedToEnd==undefined?"undefined":jumpedToEnd;}
    });
}
function finish() {
  $("#a01").finish();
}
function clear() {
  d21.textContent = "";
  d22.textContent = "";
  d23.textContent = "";
  d24.textContent = "";
}
</script>

また、上の例の jQuery の記述部分は jQuery を使用しなければ、次のように書き換えることもできます。

しかし、javascript とスタイルシートだけでは、step のようにアニメーション途中で処理を差し挟むができません(?)(繰返しごとにはできます)。この例では、アニメーション途中でも width や height を書き込むために、タイマーを設定して行っています。

また、属性ごと異なる easing を設定することもできませんので、同じ設定(ease-in-out)にしています。

<style>
@keyframes expand {
    0% {width: 0px; height: 0px; opacity:0;}
  100% {width: 200px; height: 100px; opacity:1;}
}
@keyframes contract {
    0% {width: 200px; height: 100px; opacity:1;}
  100% {width: 0px; height: 0px; opacity:0;}
}
@keyframes expandx {
    0% {width: 200px; height: 100px; opacity:1;}
  100% {width: 200px; height: 100px; opacity:1;}
}
@keyframes contractx {
    0% {width: 0px; height: 0px; opacity:0;}
  100% {width: 0px; height: 0px; opacity:0;}
}
div#a01 {
  animation-duration:5s;
  animation-timing-function:ease-in-out;
  animation-fill-mode:forwards;
  background-color: aquamarine;
}
</style>

<script>
a01.addEventListener("animationend", complete, false);

var timer = null;
var endTime = 0;
toggle();
function toggle() {
  clear();
  let dt = new Date();
  d01.textContent = dt.toLocaleString();
  if (timer != null) window.clearInterval(timer);
  timer = window.setInterval(step, 5000/100);
  endTime = dt.getTime() + 5000 ;
  a01.style.animationName = a01.style.animationName.charAt(0) == "e" ? "contract" : "expand";
  a01.style.animationPlayState = "running";
}

function step() {
  d11.textContent = a01.clientWidth + "px";
  d12.textContent = a01.clientHeight + "px";
  d13.textContent = (endTime - (new Date()).getTime()) + "mS";
}
function complete() {
  d21.textContent = "finish";
  d22.textContent = undefined;
  d24.textContent = undefined;
  d13.textContent = "0mS";
  window.clearInterval(timer);
  timer = null;
}
function finish() {
  a01.style.animationPlayState = "paused";
  a01.style.animationName = a01.style.animationName == "expand" ? "expandx" : "contractx";
  window.clearInterval(timer);
  timer = null;
  d11.textContent = a01.clientWidth + "px";
  d12.textContent = a01.clientHeight + "px";
  d13.textContent = "0mS";
  d21.textContent = "finish";
  d22.textContent = true;
  d24.textContent = true;
}

// 以下略

</script>
実行例(jQuery 使用)
実行例(jQuery 未使用)

(2-4)アニメーションのフェード

メソッド引数機能戻り値
fadeIn([時間][,イージング][,関数])時間:表示に掛ける時間(ミリ秒)(注1)(規定値:400)
イージング:変化のタイミング(注2)(規定値:swing)
関数:フェードイン後の処理
フェードインで表示するjQuery オブジェクト
fadeIn(オプション)オプション:次のキーを持つオブジェクト(注3)フェードインで表示するjQuery オブジェクト
fadeOut([時間][,イージング][,関数])時間:非表示に掛ける時間(ミリ秒)(注1)(規定値:400)
イージング:変化のタイミング(注2)(規定値:swing)
関数:フェードイン後の処理
フェードアウトして隠すjQuery オブジェクト
fadeOut(オプション)オプション:次のキーを持つオブジェクト(注3)フェードアウトして隠すjQuery オブジェクト
fadeToggle([時間][,イージング][,関数])時間:表示に掛ける時間(ミリ秒)(注1)(規定値:400)
イージング:変化のタイミング(注2)(規定値:swing)
関数:フェードイン後の処理
要素の表示・非表示を切り替えるjQuery オブジェクト
fadeToggle(オプション)オプション:次のキーを持つオブジェクト(注3)要素の表示・非表示を切り替えるjQuery オブジェクト
fadeTo(時間,透明度[,イージング][,関数])時間:表示に掛ける時間(ミリ秒)(注1)(規定値:0)
透明度:0(透明)~ 1(不透明)
イージング:変化のタイミング(注2)(規定値:swing)
関数:透明度変更後の処理
透明度を変更するjQuery オブジェクト
注1)ミリ秒以外に次のキーワードも指定できる
キーワード意味
fast200 ミリ秒
normal400 ミリ秒
slow600 ミリ秒
注2)次のキーワードが指定できる
キーワード意味
linear一定速度
swing徐々に加速し、徐々に減速

注3)次のキーワードが指定できる
キーワード意味
durationアニメーション再生時間"slow"、"normal"、"fast"、もしくは、ミリ秒(規定値:"normal")
easingイージングの種類"linear"、"swing"、もしくは関数(規定値:"swing")
function(x, t, 0, 1, d)
 x: アニメーションの進捗率(0 ~ 1)
 t: 経過時間(ミリ秒)
 d: アニメーション実行のトータル時間(ミリ秒)
 戻り値: 変化率(start と end 間の位置)(0 ~ 1)
queueアニメーション実行true:即実行、false:キューに保存(規定値:true)
specialEasing属性名ごとのイージングの種類属性名とイージングの種類からなるオブジェクト(規定値:"swing")
{
 属性名:イージングの種類,
 :
}
startアニメーション開始時の処理関数
function(Promise animation)
 animation: アニメーション情報
  elem: 要素情報
  props: 属性情報の配列
  startTime:開始時刻
  tweens:要素とその属性などの配列   など
stepアニメーション実行中のフレーム毎、プロパティ毎に呼び出される処理関数
function(Number now, Tween tween)
 now: 現在の属性値
 tween: { (アニメーションしている要素とその属性)
  elem: 要素名
  prop: 属性名
 }
progressアニメーション実行中のフレーム毎に一度だけ呼び出される処理関数
function(Promise animation, Number progress, Number remainingMs)
 animation: アニメーション情報
 progress: アニメーションの進行状況(0~1)
 remainingMs: アニメーションの残りのミリ秒(?)
completeアニメーション終了時の処理関数
function()
doneアニメーションが正常終了したときの処理関数
function(Promise animation, Boolean jumpedToEnd)
 animation: アニメーション情報
 jumpedToEnd: アニメーションの終了状況
         undefined:自然終了した
         true:finish()で目的値にして終了した
failアニメーションが異常終了したときの処理関数
function(Promise animation, Boolean jumpedToEnd)
 animation: アニメーション情報
 jumpedToEnd: アニメーションの終了状況
         undefined:stop()で目的値にせず終了した(注)仕様では false(?)
alwaysアニメーションが正常終了か異常終了か関係なく終了したときの処理関数
function(Promise animation, Boolean jumpedToEnd)
 animation: アニメーション情報
 jumpedToEnd: アニメーションの終了状況
         undefined:自然終了した
         true:finish()で目的値にして終了した
         undefined:stop()で目的値にせず終了した(注)仕様では false(?)
注)目的値:属性で指定した値(アニメーションが自然終了したときになるべき値)

○ fadeIn(属性[,時間][,イージング][,関数])、fadeOut(属性[,時間][,イージング][,関数])、   fadeToggle(属性[,時間][,イージング][,関数])

fadeIn で徐々に表示し、fadeOut で徐々に非表示になります。なお、fadeOut が完了すると display 属性が none になり、その要素が存在しない状態になります。

また、fadeToggle は、表示されていない場合は fadeIn を、表示されている場合は fadeOut を実行します。

ただし、次の例では、fadeIn と fadeOut について記述しています。また、すべての項目は設定できていませんし、得られた情報も一部のみを表示しています。

記述例
<span id="title"></span>
<div id="d01">(引数なし)</div>
<!-- 途中略 -->

<img id="d21" src="figures/bear.png">
<script>
fadeOut();

function fadeIn() {
  $("#title").text("fadeIn");
  $("#d01").fadeIn();
  $("#d02").fadeIn("fast");
  $("#d03").fadeIn("normal");
  $("#d04").fadeIn("slow");
  $("#d05").fadeIn(1000);
  $("#d11").fadeIn(3000, "linear");
  $("#d12").fadeIn(3000, "swing");
  $("#d21").fadeIn(3000, "linear");
}
function fadeOut() {
  $("#title").text("fadeOut");
  $("#d01").fadeOut();
  $("#d02").fadeOut("fast");
  $("#d03").fadeOut("normal");
  $("#d04").fadeOut("slow");
  $("#d05").fadeOut(1000);
  $("#d11").fadeOut(3000, "linear");
  $("#d12").fadeOut(3000, "swing");
  $("#d21").fadeOut(3000, "linear", fadeIn);   // 終了したら fadeIn を呼び出す
}
</script>

また、上の例の jQuery の記述部分は jQuery を使用しなければ、次のように書き換えることもできます。

<style>
@keyframes fadeIn {
  from {opacity:0;}
  to {opacity:1;}
}
@keyframes fadeOut {
  from {opacity:1;}
  to {opacity:0;}
}
</style>

<script>
d21.addEventListener("animationend", fadeIn, false);   // 終了したら fadeIn を呼び出す
var e = [].slice.call(document.querySelectorAll("div[id]"));
e.forEach(function(e, i) { e.addEventListener("animationend", none, false); });
fadeOut();

function fadeIn() {
  d21.removeEventListener("animationend", fadeIn, false);
  e.forEach(function(e, i) { e.removeEventListener("animationend", none, false); e.style.display = "block"; });
  title.textContent = "fadeIn";
  d01.style.animation = "fadeIn forwards";
  d02.style.animation = "fadeIn 200ms forwards";
  d03.style.animation = "fadeIn 400ms forwards";
  d04.style.animation = "fadeIn 600ms forwards";
  d05.style.animation = "fadeIn 1s forwards";
  d11.style.animation = "fadeIn 3s forwards linear";
  d12.style.animation = "fadeIn 3s forwards ease-in-out";
  d21.style.animation = "fadeIn 3s forwards linear";
}
function fadeOut() {
  title.textContent = "fadeOut";
  d01.style.animation = "fadeOut forwards";
  d02.style.animation = "fadeOut 200ms forwards";
  d03.style.animation = "fadeOut 400ms forwards";
  d04.style.animation = "fadeOut 600ms forwards";
  d05.style.animation = "fadeOut 1s forwards";
  d11.style.animation = "fadeOut 3s forwards linear";
  d12.style.animation = "fadeOut 3s forwards ease-in-out";
  d21.style.animation = "fadeOut 3s forwards linear";
}
function none() { this.style.display = "none"; }
</script>
実行例(jQuery 使用)
再実行
実行例(jQuery 未使用)
再実行

○ fadeToggle(オプション)、   fadeIn(オプション)、fadeOut(オプション)

先のメソッドをより詳細に設定できるようにしたものです。引数はすべてオブジェクトとして一つにまとめてありますし、設定できる項目も取得できる情報も大幅に増えています。

ただし、次の例では、fadeToggle について記述しています。また、すべての項目は設定できていませんし、得られた情報も一部のみを表示しています。

記述例
<section onclick="fadeToggle();">
  <div id="a01">click(再実行)</div>
</section>
<button class="switch" onclick="finish();">finish</button><br>

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

<script>
fadeToggle();
function fadeToggle() {
  clear();
  $("#a01").fadeToggle(
    {
      duration: 5000,
      specialEasing: {
        opacity: "linear"
      },
      start: function(animation) {var dt = new Date(animation.startTime); d01.textContent = dt.toLocaleString();},
      step: function(now, tween) { d11.textContent = now; },
      progress: function(animation, progress, remainingMs) { d13.textContent = remainingMs + "mS"; },
      complete: function() {d21.textContent = "finish";},
      done: function(animation, jumpedToEnd) {d22.textContent = jumpedToEnd==undefined?"undefined":jumpedToEnd;},
      fail: function(animation, jumpedToEnd) {d23.textContent = jumpedToEnd==undefined?"undefined":jumpedToEnd;},
      always: function(animation, jumpedToEnd) {d24.textContent = jumpedToEnd==undefined?"undefined":jumpedToEnd;}
    });
}
function finish() {
  $("#a01").finish();
}
function clear() {
  d21.textContent = "";
  d22.textContent = "";
  d23.textContent = "";
  d24.textContent = "";
}
</script>

また、上の例の jQuery の記述部分は jQuery を使用しなければ、次のように書き換えることもできます。

しかし、javascript とスタイルシートだけでは、step のようにアニメーション途中で処理を差し挟むができません(?)(繰返しごとにはできます)。この例では、アニメーション途中でも width や height を書き込むために、タイマーを設定して行っています。

また、属性ごと異なる easing を設定することもできませんので、同じ設定(ease-in-out)にしています。

<style>
@keyframes fadeIn {
    0% {opacity:0;}
  100% {opacity:1;}
}
@keyframes fadeOut {
    0% {opacity:1;}
  100% {opacity:0;}
}
@keyframes fadeInX {
    0% {opacity:1;}
  100% {opacity:1;}
}
@keyframes fadeOutX {
    0% {opacity:0;}
  100% {opacity:0;}
}
div#a01 {
  animation-duration:5s;
  animation-timing-function:ease-in-out;
  animation-fill-mode:forwards;
  background-color: aquamarine;
}
</style>

<script>
a01.addEventListener("animationend", complete, false);

var timer = null;
var endTime = 0;
fadeToggle();
function fadeToggle() {
  clear();
  let dt = new Date();
  d01.textContent = dt.toLocaleString();
  if (timer != null) window.clearInterval(timer);
  timer = window.setInterval(step, 5000/100);
  endTime = dt.getTime() + 5000 ;
  a01.style.animationName = a01.style.animationName.charAt(4) == "I" ? "fadeOut" : "fadeIn";
  a01.style.animationPlayState = "running";
}

function step() {
  d11.textContent = a01.currentStyle.opacity;
  d13.textContent = (endTime - (new Date()).getTime()) + "mS";
}
function complete() {
  d21.textContent = "finish";
  d22.textContent = undefined;
  d24.textContent = undefined;
  d13.textContent = "0mS";
  window.clearInterval(timer);
  timer = null;
}
function finish() {
  a01.style.animationPlayState = "paused";
  a01.style.animationName = a01.style.animationName == "fadeIn" ? "fadeInX" : "fadeOutX";
  window.clearInterval(timer);
  timer = null;
  d11.textContent = a01.currentStyle.opacity;
  d13.textContent = "0mS";
  d21.textContent = "finish";
  d22.textContent = true;
  d24.textContent = true;
}

// 以下略

</script>
実行例(jQuery 使用)
実行例(jQuery 未使用)

○ fadeTo(時間,透明度[,イージング][,関数])

透明度を変更します。

下の例では、ランダムな透明度に変更しています。

記述例
<section onclick="location.reload();">
  <div id="a01"></div>
</section>

<script>
var opacity = Math.random().toFixed(1);
a01.textContent = opacity;
$("#a01").fadeTo(1000, opacity, "linear", function() {a01.textContent += "(終了)";});
</script>

また、上の例の jQuery の記述部分は jQuery を使用しなければ、次のように書き換えることもできます。

<style>
@keyframes fade {
  0% {opacity:0;}
  100% {opacity:1;}
}
</style>

<script>
var anim =
  {
     name:"fade",
     animation:"fade 1s linear forwards",
     complete:function() { this.textContent += "(終了)"; }
  };
function Animation(list) {
  this.animNo = 0;
  this.animList = list == undefined ? [] : list;
  this.animCount = this.animList.length;
}
Animation.prototype.setKeyFrame = function(css, name, key, ss) {
  let rules = css.cssRules;
  let n = rules.length;
  for (let i = 0 ; i < n ; i++) {
    if (rules[i].name == name) {
      this._setKeyFrame(rules[i], key, ss);
    }
  }
}
Animation.prototype._setKeyFrame = function(rule, key, ss) {
  let n = rule.cssRules.length;
  for (let i = 0 ; i < rule.cssRules.length ; i++) {
    if (rule.cssRules[i].keyText == key) {
      rule.cssRules[i].style.cssText = ss;
      break;
    }
  }
}

var styleSheet = document.styleSheets[0];      // 複数定義されているスタイルシートの1番目
var animation = new Animation([anim]);
a01.addEventListener("animationend", function() {anim.complete.apply(a01)}, false);
a01.style.animation = "";
var opacity = Math.random().toFixed(1);
a01.textContent = opacity;
animation.setKeyFrame(styleSheet, "fade", "0%", "opacity:0");
animation.setKeyFrame(styleSheet, "fade", "100%", "opacity:" + opacity);
a01.style.animation = anim.animation;
</script>
実行例(jQuery 使用)
実行例(jQuery 未使用)

(2-5)アニメーションのスライド

メソッド引数機能戻り値
slideDown([時間][,イージング][,関数])時間:表示に掛ける時間(ミリ秒)(注1)(規定値:400)
イージング:変化のタイミング(注2)(規定値:swing)
関数:スライドダウン後の処理
スライドダウンで表示するjQuery オブジェクト
slideDown(オプション)オプション:次のキーを持つオブジェクト(注3)スライドダウンで表示するjQuery オブジェクト
slideUp([時間][,イージング][,関数])時間:非表示に掛ける時間(ミリ秒)(注1)(規定値:400)
イージング:変化のタイミング(注2)(規定値:swing)
関数:スライドアップ後の処理
スライドアップで表示するjQuery オブジェクト
slideUp(オプション)オプション:次のキーを持つオブジェクト(注3)スライドアップで表示するjQuery オブジェクト
slideToggle([時間][,イージング][,関数])時間:表示に掛ける時間(ミリ秒)(注1)(規定値:400)
イージング:変化のタイミング(注2)(規定値:swing)
関数:ライドアップ後の処理
スライドダウンとスライドアップの表示を切り替えるjQuery オブジェクト
slideToggle(オプション)オプション:次のキーを持つオブジェクト(注3)スライドダウンとスライドアップの表示を切り替えるjQuery オブジェクト
注1)ミリ秒以外に次のキーワードも指定できる
キーワード意味
fast200 ミリ秒
normal400 ミリ秒
slow600 ミリ秒
注2)次のキーワードが指定できる
キーワード意味
linear一定速度
swing徐々に加速し、徐々に減速

注3)次のキーワードが指定できる
キーワード意味
durationアニメーション再生時間"slow"、"normal"、"fast"、もしくは、ミリ秒(規定値:"normal")
easingイージングの種類"linear"、"swing"、もしくは関数(規定値:"swing")
function(x, t, 0, 1, d)
 x: アニメーションの進捗率(0 ~ 1)
 t: 経過時間(ミリ秒)
 d: アニメーション実行のトータル時間(ミリ秒)
 戻り値: 変化率(start と end 間の位置)(0 ~ 1)
queueアニメーション実行true:即実行、false:キューに保存(規定値:true)
specialEasing属性名ごとのイージングの種類属性名とイージングの種類からなるオブジェクト(規定値:"swing")
{
 属性名:イージングの種類,
 :
}
startアニメーション開始時の処理関数
function(Promise animation)
 animation: アニメーション情報
  elem: 要素情報
  props: 属性情報の配列
  startTime:開始時刻
  tweens:要素とその属性などの配列   など
stepアニメーション実行中のフレーム毎、プロパティ毎に呼び出される処理関数
function(Number now, Tween tween)
 now: 現在の属性値
 tween: { (アニメーションしている要素とその属性)
  elem: 要素名
  prop: 属性名
 }
progressアニメーション実行中のフレーム毎に一度だけ呼び出される処理関数
function(Promise animation, Number progress, Number remainingMs)
 animation: アニメーション情報
 progress: アニメーションの進行状況(0~1)
 remainingMs: アニメーションの残りのミリ秒(?)
completeアニメーション終了時の処理関数
function()
doneアニメーションが正常終了したときの処理関数
function(Promise animation, Boolean jumpedToEnd)
 animation: アニメーション情報
 jumpedToEnd: アニメーションの終了状況
         undefined:自然終了した
         true:finish()で目的値にして終了した
failアニメーションが異常終了したときの処理関数
function(Promise animation, Boolean jumpedToEnd)
 animation: アニメーション情報
 jumpedToEnd: アニメーションの終了状況
         undefined:stop()で目的値にせず終了した(注)仕様では false(?)
alwaysアニメーションが正常終了か異常終了か関係なく終了したときの処理関数
function(Promise animation, Boolean jumpedToEnd)
 animation: アニメーション情報
 jumpedToEnd: アニメーションの終了状況
         undefined:自然終了した
         true:finish()で目的値にして終了した
         undefined:stop()で目的値にせず終了した(注)仕様では false(?)
注)目的値:属性で指定した値(アニメーションが自然終了したときになるべき値)

○ slideUp(属性[,時間][,イージング][,関数])、slideDown(属性[,時間][,イージング][,関数])、   slideToggle(属性[,時間][,イージング][,関数])

slideUp で縦方向に縮小して要素を隠し、slideDown で縦方向に拡大して表示します。なお、slideUp が完了すると display 属性が none になり、その要素が存在しない状態になります。

また、fadeToggle は、表示されていない場合は slideUp を、表示されている場合は slideDown を実行します。

ただし、次の例では、slideUp と slideDown について記述しています。また、すべての項目は設定できていませんし、得られた情報も一部のみを表示しています。

記述例
<span id="title"></span>
<div id="d01">(引数なし)</div>
<!-- 途中略 -->

<img id="d21" src="figures/bear.png">
<script>
slideUp();

function slideUp() {
  $("#title").text("slideUp");
  $("#d01").slideUp();
  $("#d02").slideUp("fast");
  $("#d03").slideUp("normal");
  $("#d04").slideUp("slow");
  $("#d05").slideUp(1000);
  $("#d11").slideUp(3000, "linear");
  $("#d12").slideUp(3000, "swing");
  $("#d21").slideUp(3000, "linear", slideDown);   // 終了したら slideDown を呼び出す
}
function slideDown() {
  $("#title").text("fadeOut");
  $("#d01").slideDown();
  $("#d02").slideDown("fast");
  $("#d03").slideDown("normal");
  $("#d04").slideDown("slow");
  $("#d05").slideDown(1000);
  $("#d11").slideDown(3000, "linear");
  $("#d12").slideDown(3000, "swing");
  $("#d21").slideDown(3000, "linear");
}
</script>

また、上の例の jQuery の記述部分は jQuery を使用しなければ、次のように書き換えることもできます。

<style>
@keyframes slideDown {
  from {height: 0px;}
  to {height: 20px;}
}
@keyframes slideDownImg {
  from {height: 0px;}
  to {height: 74px;}
}
@keyframes slideUp {
  from {height: 20px;}
  to {height: 0px;}
}
@keyframes slideUpImg {
  from {height: 74px;}
  to {height: 0px;}
}
</style>

<script>
d21.addEventListener("animationend", slideDown, false);   // 終了したら slideDown を呼び出す
var e = [].slice.call(document.querySelectorAll("div[id]"));
e.forEach(function(e, i) { e.addEventListener("animationend", none, false); });
slideUp();

function slideUp() {
  d21.removeEventListener("animationend", slideUp, false);
  e.forEach(function(e, i) { e.removeEventListener("animationend", none, false); e.style.display = "block"; });
  title.textContent = "slideUp";
  d01.style.animation = "slideUp forwards";
  d02.style.animation = "slideUp 200ms forwards";
  d03.style.animation = "slideUp 400ms forwards";
  d04.style.animation = "slideUp 600ms forwards";
  d05.style.animation = "slideUp 1s forwards";
  d11.style.animation = "slideUp 3s forwards linear";
  d12.style.animation = "slideUp 3s forwards ease-in-out";
  d21.style.animation = "slideUpImg 3s forwards linear";
}
function slideDown() {
  title.textContent = "slideDown";
  d01.style.animation = "slideDown forwards";
  d02.style.animation = "slideDown 200ms forwards";
  d03.style.animation = "slideDown 400ms forwards";
  d04.style.animation = "slideDown 600ms forwards";
  d05.style.animation = "slideDown 1s forwards";
  d11.style.animation = "slideDown 3s forwards linear";
  d12.style.animation = "slideDown 3s forwards ease-in-out";
  d21.style.animation = "slideDownImg 3s forwards linear";
}
function none() { this.style.display = "none"; }
</script>
実行例(jQuery 使用)
再実行
実行例(jQuery 未使用)
再実行

○ slideToggle(オプション)、   slideIn(オプション)、slideOut(オプション)

先のメソッドをより詳細に設定できるようにしたものです。引数はすべてオブジェクトとして一つにまとめてありますし、設定できる項目も取得できる情報も大幅に増えています。

ただし、次の例では、slideToggle について記述しています。また、すべての項目は設定できていませんし、得られた情報も一部のみを表示しています。

記述例
<section onclick="fadeToggle();">
  <div id="a01">click(再実行)</div>
</section>
<button class="switch" onclick="finish();">finish</button><br>

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

<script>
fadeToggle();
function fadeToggle() {
  clear();
  $("#a01").fadeToggle(
    {
      duration: 5000,
      specialEasing: {
        width: "swing",
        height: "linear"
      },
      start: function(animation) {let dt = new Date(animation.startTime); d01.textContent = dt.toLocaleString();},
      step: function(now, tween) { d11.textContent = now; },
      progress: function(animation, progress, remainingMs) { d13.textContent = remainingMs + "mS"; },
      complete: function() {d21.textContent = "finish";},
      done: function(animation, jumpedToEnd) {d22.textContent = jumpedToEnd==undefined?"undefined":jumpedToEnd;},
      fail: function(animation, jumpedToEnd) {d23.textContent = jumpedToEnd==undefined?"undefined":jumpedToEnd;},
      always: function(animation, jumpedToEnd) {d24.textContent = jumpedToEnd==undefined?"undefined":jumpedToEnd;}
    });
}
function finish() {
  $("#a01").finish();
}
function clear() {
  d21.textContent = "";
  d22.textContent = "";
  d23.textContent = "";
  d24.textContent = "";
}
</script>

また、上の例の jQuery の記述部分は jQuery を使用しなければ、次のように書き換えることもできます。

しかし、javascript とスタイルシートだけでは、step のようにアニメーション途中で処理を差し挟むができません(?)(繰返しごとにはできます)。この例では、アニメーション途中でも height を書き込むために、タイマーを設定して行っています。

また、属性ごと異なる easing を設定することもできませんので、同じ設定(ease-in-out)にしています。

<style>
@keyframes slideIn {
  from {height:0px;}
  to {height:30px;}
}
@keyframes slideOut {
  from {height:30px;}
  to {height:0px;}
}
@keyframes slideInX {
  from {height:30px;}
  to {height:0px;}
}
@keyframes slideOutX {
  from {height:0px;}
  to {height:0px;}
}
div#a01 {
  animation-duration:5s;
  animation-timing-function:ease-in-out;
  animation-fill-mode:forwards;
  background-color: aquamarine;
}
</style>

<script>
a01.addEventListener("animationend", complete, false);

var timer = null;
var endTime = 0;
slideToggle();
function slideToggle() {
  clear();
  let dt = new Date();
  d01.textContent = dt.toLocaleString();
  if (timer != null) window.clearInterval(timer);
  timer = window.setInterval(step, 5000/100);
  endTime = dt.getTime() + 5000 ;
  a01.style.animationName = a01.style.animationName.charAt(5) == "I" ? "slideOut" : "slideIn";
  a01.style.animationPlayState = "running";
}

function step() {
  d11.textContent = a01.clientHeight;
  d13.textContent = (endTime - (new Date()).getTime()) + "mS";
}
function complete() {
  d21.textContent = "finish";
  d22.textContent = undefined;
  d24.textContent = undefined;
  d13.textContent = "0mS";
  window.clearInterval(timer);
  timer = null;
}
function finish() {
  a01.style.animationPlayState = "paused";
  a01.style.animationName = a01.style.animationName == "slideIn" ? "slideInX" : "slideOutX";
  window.clearInterval(timer);
  timer = null;
  d11.textContent = a01.clientHeight;
  d13.textContent = "0mS";
  d21.textContent = "finish";
  d22.textContent = true;
  d24.textContent = true;
}

// 以下略

</script>
実行例(jQuery 使用)
実行例(jQuery 未使用)

(2-6)アニメーションのキュー

メソッド引数機能戻り値
queue([キュー名])キュー名:アニメーションのキューの名前(規定値:fx)アニメーションのキューを取得するアニメーション関数などの配列(注)
queue([キュー名,]配列)キュー名:アニメーションのキューの名前(規定値:fx)
配列:アニメーション関数などの配列(注)
アニメーションのキューを変更するjQuery オブジェクト
queue([キュー名,]関数)キュー名:アニメーションのキューの名前(規定値:fx)
関数:キューに追加する処理
アニメーションのキューを設定するjQuery オブジェクト
dequeue([キュー名])キュー名:アニメーションのキューの名前(規定値:fx)アニメーションの次のキューを実行するjQuery オブジェクト
clearQueue([キュー名])キュー名:アニメーションのキューの名前(規定値:fx)アニメーションのキューを空にする
clearQueue() は queue([]) と同じ
jQuery オブジェクト
注)配列の内容
 先頭要素:"inprogress"
 2番目以降の要素:function(){let t=pt(this,w.extend({},e),o);(i||J.get(this,"finish"))&&t.stop(!0)} のような関数
実質的には length プロパティを利用してアニメーションの数を取得するか、空の配列([])を設定して登録されたアニメーションをキャンセルすることくらいしか使わないようです。

○ queue、clearQueue

「スタート」ボタンをクリックすると、矩形が移動します。そのとき、矩形の中には残りのアニメーション・キューの数が表示されます。キューの数はアニメーションが実行されるたびに減っていきます。

「ストップ」ボタンをクリックすると、残っているキューを空にします。その結果、アニメーションは終了します。

なお、関数を引数とする queue の例は、次の dequeue を参照してください。

記述例
<button onclick="start();">スタート</button> <button onclick="stop();">ストップ</button>
<div id="a01" style="position:relative;width:30px;height:30px;"></div>

<script>
function start() {
  a01.style.top = "0px";
  a01.style.left = "0px";
  $("#a01").clearQueue();
  $("#a01").animate({left:100}, 1000, count);
  $("#a01").animate({top:40}, 400, count);
  $("#a01").animate({left:0}, 1000, count);
  $("#a01").animate({top:0}, 400, count);
  a01.textContent = $("#a01").queue().length - 1;
}
function stop() { $("#a01").queue([]); }
function count() { let count = $("#a01").queue().length; a01.textContent = count > 1 ? count - 2 : 0; }
</script>

また、上の例の jQuery の記述部分は jQuery を使用しなければ、次のように書き換えることもできます。

<style>
@keyframes home {
  from {top:0px;left:0px;}
  to {top:0px;left:0px;}
}
@keyframes right {
  from {top:0px;left:0px;}
  to {top:0px;left:100px;}
}
@keyframes down {
  from {top:0px;left:100px;}
  to {top:40px;left:100px;}
}
@keyframes left {
  from {top:40px;left:100px;}
  to {top:40px;left:0px;}
}
@keyframes up {
  from {top:40px;left:0px;}
  to {top:0px;left:0px;}
}
</style>

<script>
a01.addEventListener("animationend", next, false);

var queue = [];
function start() {
  a01.textContent = "";
  queue = [];
  queue.push("home 0ms forwards");
  queue.push("right 1000ms forwards");
  queue.push("down 400ms forwards");
  queue.push("left 1000ms forwards");
  queue.push("up 400ms forwards");
  next();
}
function next() {
  if (queue.length > 0)
    a01.style.animation = queue.shift();
  count();
}
function stop() { queue = []; }
function count() { a01.textContent = queue.length; }
</script>
実行例(jQuery 使用)
実行例(jQuery 未使用)

○ dequeue

「スタート」ボタンをクリックすると、矩形が移動します。そのとき、上側の矩形は途中で止まってしまいますが、下側の矩形は最後まで移動します。

関数を引数とした queue は、関数で指定した処理をキューに追加します。しかし、キューに追加された処理にアニメーションがあったとしてもそのままでは処理されません(アニメーション以外は処理されます)。そこで、アニメーションを処理するために、dequeue を実行します。

下側の矩形は dequeue を実行していますので、最後まで実行されます。

記述例
<button onclick="start();">スタート</button>
<div id="a01" style="position:relative;width:30px;height:30px;"></div>
<div id="a02" style="position:relative;width:30px;height:30px;"></div>

<script>
function start() {
  anim("a01", false);
  anim("a02", true);       // dequeue を実行する
}
function anim(id, deq) {
  let a = document.getElementById(id);
  a.style.top = "0px";
  a.style.left = "0px";
  let jid = "#" + id;
  $(jid).css({backgroundColor:"aquamarine"});
  $(jid).text("A");
  $(jid).clearQueue();
  $(jid).animate({left:100}, 1000,);
  $(jid).animate({top:40}, 400,);
  $(jid).queue(function() {       // 処理を追加する
    $(jid).animate({left:0}, 1000,);
    $(jid).css({backgroundColor:"lime"});
    $(jid).animate({top:0}, 400,);
    $(jid).text("B");
    if (deq) $(this).dequeue();
  });
}
</script>

また、上の例の jQuery の記述部分は jQuery を使用しなければ、次のように書き換えることもできます。

<style>
@keyframes home {
  from {top:0px;left:0px;}
  to {top:0px;left:0px;}
}
@keyframes right {
  from {top:0px;left:0px;}
  to {top:0px;left:100px;}
}
@keyframes down {
  from {top:0px;left:100px;}
  to {top:40px;left:100px;}
}
@keyframes left {
  from {top:40px;left:100px;}
  to {top:40px;left:0px;}
}
@keyframes up {
  from {top:40px;left:0px;}
  to {top:0px;left:0px;}
}
</style>

<script>
var queue1 = [];
var queue2 = [];
a01.addEventListener("animationend", function() {next("a01", queue1);}, false);
a02.addEventListener("animationend", function() {next("a02", queue2);}, false);

function start() {
  anim("a01", false);
  anim("a02", true);
}
function anim(id, deq) {
  let a = document.getElementById(id);
  a.style.animation = "home 0ms forwards";
  a.style.top = "0px";
  a.style.left = "0px";
  a.style.backgroundColor = "aquamarine";
  a.textContent = "A";
  queue = id == "a01" ? queue1 : queue2;
  queue.push("right 1000ms forwards");
  queue.push("down 400ms forwards");
  queue.push(function(q) {
    if (deq) q.push("left 1000ms forwards");
    a.style.backgroundColor = "lime";
    if (deq) q.push("up 400ms forwards");
    a.textContent = "B";
  });
  next(id, queue);
}
function next(id, queue) {
  if (queue.length > 0) {
    let a = document.getElementById(id);
    let obj = queue.shift();
    if (obj instanceof Function) {
      obj.apply(a, [queue]);
      next(id, queue);
    }
    else
      a.style.animation = obj;
  }
}
</script>
実行例(jQuery 使用)
実行例(jQuery 未使用)

13.3.13  ユーティリティ

様々な機能をもったユーティリティーメソッドです。

(1)チェック

(1-1)存在チェック

メソッド引数機能戻り値
$.contains(対象要素,検索要素)対象要素:調べる対象となるDOM要素
検索要素:存在を調べたいDOM要素
検索要素が、対象要素に含まれているかどうかを判定するtrue:含む、false:含まない

記述例
<span id="a"><span id="b"></span></span><br>
<span id="d01"></span> <span id="d02"></span><br>
<span id="d11"></span> <span id="d12"></span><br>
<script>
$("d01").text($.contains(document.body, document.getElementById("a")));       // 含む
$("d02").text($.contains(document.body, document.getElementById("x")));       // 含まない
$("d11").text($.contains(document.getElementById("a"), document.getElementById("b")));       // 含む
$("d12").text($.contains(document.getElementById("b"), document.getElementById("a")));       // 含まない
</script>

また、上の例の jQuery の記述部分は jQuery を使用しなければ、次のように書き換えることもできます。

d01.textContent = document.body.contains(document.getElementById("a"));       // 含む
d02.textContent = document.body.contains(document.getElementById("x"));       // 含まない
d11.textContent = document.getElementById("a").contains(document.getElementById("b"));       // 含む
d12.textContent = document.getElementById("b").contains(document.getElementById("a"));       // 含まない
実行例(jQuery 使用)
実行例(jQuery 未使用)

(1-2)数値チェック

メソッド引数機能戻り値
$.isNumeric(要素)要素:調べる対象となるオブジェクト要素が、数値かどうかを判定する(注)true:数値、false:数値でない
注)数値からなる文字列や8進数、16進数、指数表現、Number オブジェクトの定数も数値と判断される
(ただし、Infinity や Number.NEGATIVE_INFINITY、Number.POSITIVE_INFINITY は数値とはみなされない)

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

<script>
$("d01").text($.isNumeric(null));
$("d02").text($.isNumeric(Infinity));
$("d03").text($.isNumeric(Number.NEGATIVE_INFINITY));
$("d04").text($.isNumeric("1-"));
$("d11").text($.isNumeric(10));
$("d12").text($.isNumeric("-10"));
$("d13").text($.isNumeric(0xFF));
$("d14").text($.isNumeric(0777));
$("d15").text($.isNumeric(5e3));
$("d16").text($.isNumeric(Number.MIN_VALUE));
$("d17").text($.isNumeric(Number.MIN_SAFE_INTEGER));
</script>

また、上の例の jQuery の記述部分は jQuery を使用しなければ、次のように書き換えることもできます。

d01.textContent = isNumeric(null);
d02.textContent = isNumeric(Infinity);
d03.textContent = isNumeric(Number.NEGATIVE_INFINITY);
d04.textContent = isNumeric("1-");
d11.textContent = isNumeric(10);
d12.textContent = isNumeric("-10");
d13.textContent = isNumeric(0xFF);
d14.textContent = isNumeric(0777);
d15.textContent = isNumeric(5e3);
d16.textContent = isNumeric(Number.MIN_VALUE);
d17.textContent = isNumeric(Number.MIN_SAFE_INTEGER);

function isNumeric(d) {
  if (d == null) return false;
  return isFinite(d);
}

の Number オブジェクトは、EPSILON、MIN_SAFE_INTEGER、MAX_SAFE_INTEGER をサポートしていませんので false となります。

実行例(jQuery 使用)
実行例(jQuery 未使用)

(1-3)オブジェクト・チェック

メソッド引数機能戻り値
$.isEmptyObject(要素)要素:調べる対象となるオブジェクト要素が、空のオブジェクトかどうかを判定する
(注)要素がオブジェクトでない場合は正しい結果が得られない可能性がある
true:空、false:空でない
$.isArray(要素)要素:調べる対象となるオブジェクト要素が、配列かどうかを判定するtrue:配列、false:配列でない
$.isPlainObject(要素)要素:調べる対象となるオブジェクト要素が、オブジェクトかどうかを判定するtrue:オブジェクト、false:オブジェクトでない
$.isFunction(要素)要素:調べる対象となるオブジェクト要素が、関数かどうかを判定するtrue:関数、false:関数でない
$.isWindow(要素)要素:調べる対象となるオブジェクト要素が、window オブジェクトかどうかを判定するtrue:window 、false:window でない
$.isXMLDoc(要素)要素:調べる対象となるオブジェクト要素が、XML オブジェクトかどうかを判定するtrue:XML、false:XML でない

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

<script>
var f1 = function() {};
function f2() {}
var f3 = () => 0;       // アロー関数式

$("#d01").text($.isEmptyObject(null));
$("#d02").text($.isEmptyObject([]));
$("#d03").text($.isEmptyObject({}));
$("#d04").text($.isEmptyObject(""));
$("#d05").text($.isEmptyObject([0]));
$("#d06").text($.isEmptyObject({a:0}));
$("#d07").text($.isEmptyObject("0"));
$("#d11").text($.isArray([]));
$("#d12").text($.isArray([0]));
$("#d13").text($.isArray(null));
$("#d14").text($.isArray(undefined));
$("#d15").text($.isArray(""));
$("#d16").text($.isArray({}));
$("#d21").text($.isPlainObject({}));
$("#d22").text($.isPlainObject({a:0}));
$("#d23").text($.isPlainObject(null));
$("#d24").text($.isPlainObject(undefined));
$("#d25").text($.isPlainObject(""));
$("#d26").text($.isPlainObject([]));
$("#d31").text($.isFunction(f1));
$("#d32").text($.isFunction(f2));
$("#d33").text($.isFunction(f3));
$("#d34").text($.isFunction(null));
$("#d41").text($.isWindow(window));
$("#d42").text($.isWindow(this));
$("#d43").text($.isWindow(null));
$("#d44").text($.isWindow(document));
$("#d51").text($.isXMLDoc($.parseXML("<name>Taro</name>")));
$("#d52").text($.isXMLDoc("<name>Taro</name>"));
</script>

また、上の例の jQuery の記述部分は jQuery を使用しなければ、次のように書き換えることもできます。

d01.textContent = isEmptyObject(null);
d02.textContent = isEmptyObject([]);
d03.textContent = isEmptyObject({});
d04.textContent = isEmptyObject("");
d05.textContent = isEmptyObject([0]);
d06.textContent = isEmptyObject({a:0});
d07.textContent = isEmptyObject("0");
d11.textContent = isArray([]);
d12.textContent = isArray([0]);
d13.textContent = isArray(null);
d14.textContent = isArray(undefined);
d15.textContent = isArray("");
d16.textContent = isArray({});
d21.textContent = isPlainObject({});
d22.textContent = isPlainObject({a:0});
d23.textContent = isPlainObject(null);
d24.textContent = isPlainObject(undefined);
d25.textContent = isPlainObject("");
d26.textContent = isPlainObject([]);
d31.textContent = isFunction(f1);
d32.textContent = isFunction(f2);
d33.textContent = isFunction(f3);
d34.textContent = isFunction(null);
d41.textContent = isWindow(window);
d42.textContent = isWindow(this);
d43.textContent = isWindow(null);
d44.textContent = isWindow(document);
d51.textContent = isXMLDoc(document.implementation.createDocument("", "", null));
d52.textContent = isXMLDoc("<name>Taro</name>");

function isEmptyObject(d) {
  if (d === null || d === undefined) return true;
  if (d == [] || d == "") return true;
  if (typeof d == "object") {
    if (Object.keys(d).length == 0) return true;
  }
  return false;
}
function isArray(d) {
  return Array.isArray(d);
}
function isPlainObject(d) {
  if (d === null || Array.isArray(d)) return false;
  return typeof d == "object";
}
function isFunction(d) {
  return typeof d == "function";
}
function isWindow(d) {
  return d === window;
}
function isXMLDoc(d) {
  return d instanceof XMLDocument;
}
実行例(jQuery 使用)
実行例(jQuery 未使用)

(2)配列・オブジェクト操作

(2-1)配列

メソッド引数機能戻り値
$.inArray(,配列 [,位置])値:検索する値
配列:検索対象の配列
位置:検索開始位置(0~)(規定値:0)
値が、配列に含まれているかどうかを判定する存在位置(0~)
-1:見つからない
$.grep(配列,関数 [,反転])配列:対象となる配列
関数:フィルタリング関数
関数の形式
function(element, index)
 element: 対象となる要素
 index:   要素番号(0~)
戻り値:  true/false
反転:trueのときは関数がfalseを返した要素、falseのときはtrueを返した要素で配列を生成する(規定値:false)
フィルタ条件を満たす配列要素だけを取り出す配列
$.merge(配列1,配列2)配列1:マージ対象の配列(配列2が追加され変更される)
配列2:追加する配列
配列1に配列2を追加するマージされた配列
(配列1と同じ)
$.unique(配列)配列:処理対象のDOM要素の配列
(文字列や数値の配列では使用できない)
配列内の重複しているDOM要素を探しだして削除する配列

記述例
<span id="s1"></span><span id="s2" class="x"></span><span id="s3"></span>
<div id="d1" class="x"></span>

<table>
 <tr><td id="d01"></td><td id="d02"></td><td id="d03"></td></tr>
 <!-- 途中略 -->
</table>

<script>
$("#d01").text($.inArray(2, [0,1,2,3]));
$("#d02").text($.inArray(2, [0,1,2,3], 2));
$("#d03").text($.inArray(2, [0,1,2,3], 3));
$("#d11").text($.grep([0,1,2,3],function(e,i){return e % 2 == 0 ? true : false;}));
$("#d12").text($.grep([0,1,2,3],function(e,i){return e % 2 == 0 ? true : false;}, true));
var e1 = $("span");           // span 要素
var e2 = $(".x");             // class="x" の要素
$.merge(e1, e2);
$("#d21").text(getId(e1));
$("#d22").text($.merge([0,1],[2,3]));
$("#d31").text(getId($.unique(e1)));
$("#d32").text($.unique([0,1,0,3]));           // 数値の配列には無効

function getId(array) {
  let s = "";
  for (let i = 0 ; i < array.length ; i++) {
    s += array[i].id + " ";           // 要素の ID を連結
  }
  return s;
}
</script>

また、上の例の jQuery の記述部分は jQuery を使用しなければ、次のように書き換えることもできます。

なお、[].slice.call は Array.prototype.slice.call と書くこともでき、querySelectorAll などの戻り値を Array オブジェクトに変換します。

d01.textContent = [0,1,2,3].indexOf(2);
d02.textContent = [0,1,2,3].indexOf(2, 2);
d03.textContent = [0,1,2,3].indexOf(2, 3);
d11.textContent = [0,1,2,3].filter(function(e, i){return e % 2 == 0;});
d12.textContent = [0,1,2,3].filter(function(e, i){return e % 2 != 0;});
var e1 = [].slice.call(document.querySelectorAll("span"));
var e2 = [].slice.call(document.querySelectorAll(".x"));
e1 = e1.concat(e2);
d21.textContent = getId(e1);
d22.textContent = [0,1].concat([2,3]);
d31.textContent = getId(unique(e1));
d32.textContent = unique([0,1,0,3]);

function unique(array) {
  return array.filter(function(e, i, array) {return i == 0 ? true : array.lastIndexOf(e, i - 1) < 0;});
}

// 以下略

数値の配列に対しては、merge は有効ですが、unique は機能しません。ただし、jQuery 未使用の方は共に機能します。

実行例(jQuery 使用)
実行例(jQuery 未使用)

(2-2)オブジェクト

メソッド引数機能戻り値
$.each(配列/オブジェクト, 関数)配列/オブジェクト:配列またはオブジェクト
関数:処理関数
関数の形式
function(index, value)
 index: 配列のとき要素番号(0~)
     オブジェクトのときキー  value: 対象となる値 戻り値: true/false
    (false を返すと処理を中止する)
配列/オブジェクトの各要素に対して繰り返し処理を行う配列/オブジェクト
(一つ目の引数と同じ)
$.map(配列/オブジェクト, 関数)配列/オブジェクト:配列またはオブジェクト
関数:処理関数
関数の形式
function(element, index)
 element: 対象となる要素
 index: 配列のとき要素番号(0~)
     オブジェクトのときキー 戻り値: 値(null を返すと
     その要素を削除することになる)
配列/オブジェクトの各要素に対して繰り返し処理を行い配列として返す配列
$.extend([ディープコピー, ]
     対象オブジェクト
     [, オブジェクト[, オブジェクト]])
ディープコピー:オブジェクト内のオブジェクトの
        コピーをする(true)か、しない(false)か(規定値:false)
対象オブジェクト:コピー先オブジェクト
オブジェクト:コピー元オブジェクト
オブジェクトの各要素のコピーを行う(注)オブジェクト
(対象オブジェクトと同じ)
注)配列を指定すると最後の配列が対象オブジェクトにコピーされるだけ

○ each、map

記述例
<span id="s1"></span><span id="s2"></span><span id="s3"></span>

<table>
 <tr><td id="d00"></td><td id="d01"></td><td id="d02"></td></tr>
 <!-- 途中略 -->
</table>

<script>
$.each([2,3,5,7], function(i, v){$("#d0"+i).text(v);});
$.each($("span"), function(i, v){$("#d1"+i).text(v.id);});
var x = 0;
$.each({a:0,b:1,c:2}, function(i, v){$("#d2"+x++).text(i + ":" + v);});

$("#d30").text($.map([2,3,5,7], function(e, i){return e * 2;}));
$("#d40").text($.map($("span"), function(e, i){return e.id;}));
$("#d50").text($.map({a:0,b:1,c:2}, function(e, i){return e;}));
</script>

また、上の例の jQuery の記述部分は jQuery を使用しなければ、次のように書き換えることもできます。

ただし、関数の戻り値による処理には対応していません。

なお、[].slice.call は Array.prototype.slice.call と書くこともでき、querySelectorAll などの戻り値を Array オブジェクトに変換します。

[2,3,5,7].forEach(function(e, i, array){document.getElementById("d0"+i).textContent = e;});
var e = [].slice.call(document.querySelectorAll("span"));
e.forEach(function(e, i, array){document.getElementById("d1"+i).textContent = e.id;});
var x = 0;
each({a:0,b:1,c:2}, function(i, v){document.getElementById("d2"+x++).textContent = i + ":" + v;});

var a = [2,3,5,7];
a.forEach(function(e, i, array){array[i] = e * 2;});
d30.textContent = a;
var e = [].slice.call(document.querySelectorAll("span"));
e.forEach(function(e, i, array){array[i] = e.id;});
d40.textContent = e;
d50.textContent = map({a:0,b:1,c:2}, function(e, i){return e;});

function each(obj, func) {
  let keys = Object.keys(obj);
  keys.forEach(function(e, i, array){func(e, obj[e]);});
}
function map(obj, func) {
  let keys = Object.keys(obj);
  let vals = [];
  keys.forEach(function(e, i, array){vals[i] = func(obj[e], e);});
  return vals;
}
実行例(jQuery 使用)
実行例(jQuery 未使用)

○ extend

記述例
<span id="d00"></span><span id="d01"></span> <!-- 途中略 --> <span id="s05"></span>
<span id="d10"></span><span id="d11"></span> <!-- 途中略 --> <span id="s15"></span>

<script>
var t = {};
var s1 = {
  a:1,
  b:{b1:0, b2:2},
  c:0
};
var s2 = {
  b:{b2:11, b3:12},
  c:3,
  d:4
};
var n = 0;
disp($.extend(t, s1, s2), "d0");
n = 0;
disp($.extend(true, {}, s1, s2), "d1");

function disp(obj, id) {
  let keys = Object.keys(obj);
  keys.forEach(function(v, i, array){
    if (typeof obj[v] == "object")
      disp(obj[v], id);
    else
      document.getElementById(id+n++).textContent = v + ":" + obj[v];
  });
}
</script>

また、上の例の jQuery の記述部分は jQuery を使用しなければ、次のように書き換えることもできます。

ただし、配列には対応していません。

// これより前は略
var n = 0;
disp(extend(t, s1, s2), "d0");
n = 0;
disp(extend(true, {}, s1, s2), "d1");

function extend(p1, p2, p3, p4) {
  if (typeof p1 != "boolean")
    return _extend1(p1, p2, p3);
  else
    if (p1)
      return _extend2(p2, p3, p4);
    else
      return _extend1(p2, p3, p4);
}

function _extend1(target, src1, src2) {
  target = _clone(src1);
  var keys = Object.keys(src2);
  keys.forEach(function(v, i, array){ target[v] = src2[v]; });
  return target;
}
function _extend2(target, src1, src2) {
  if (src1 != null) target = _clone(src1);
  let keys = Object.keys(src2);
  keys.forEach(function(v, i, array){
    if (typeof src2[v] != "object")
      target[v] = src2[v]; 
    else
      _extend2(target[v], null, src2[v]);
  });
  return target;
}

function _clone(s) {           // ディープコピー
  let d = {};
  let keys = Object.keys(s);
  keys.forEach(function(v, i, array){
    if (typeof s[v] != "object")
      d[v] = s[v];
    else
      d[v] = _clone(s[v]);
  });
  return d;
}

// 以下略

実行例(jQuery 使用)
実行例(jQuery 未使用)

(2-3)jQuery オブジェクト

メソッド引数機能戻り値
$.makeArray(jQuery)jQuery:配列に変換したい jQuery オブジェクト配列に変換する配列

記述例
<span id="s01"></span><span id="s02" class="x"></span><span id="s03"></span>
<script>
$("#d01").text(getId($.makeArray($("span"))));

function getId(array) {
  let s = "";
  for (let i = 0 ; i < array.length ; i++) {
    s += array[i].id + " ";           // 要素の ID を連結
  }
  return s;
}
</script>

また、上の例の jQuery の記述部分は jQuery を使用しなければ、次のように書き換えることもできます。

なお、[].slice.call は Array.prototype.slice.call と書くこともでき、querySelectorAll などの戻り値を Array オブジェクトに変換します。

d01.textContent = getId(makeArray(document.querySelectorAll("span")));

function makeArray(d) {
  return [].slice.call(d);
}

// 以下略

実行例(jQuery 使用)
実行例(jQuery 未使用)

(3)関数

(3-1)関数の実行

メソッド引数機能戻り値
$.proxy(関数, コンテキスト[, 引数])関数:実行する関数
コンテキスト:関数内で実行されるthisに設定するオブジェクト
引数:関数へ渡される引数
関数内で実行されるthisを任意のオブジェクトに変更する関数
$.proxy(コンテキスト, 関数名[, 引数])コンテキスト:関数内で実行されるthisに設定するオブジェクト
関数名:実行する関数の名前
引数:関数へ渡される引数
関数内で実行されるthisを任意のオブジェクトに変更する関数

関数内で参照している this オブジェクトを引数のオブジェクトで置き換えて実行します。

記述例
<span id="d01"></span><br>
<span id="d02"></span><br>
<script>
function bird(d){
  d.textContent = this.name + "が" + this.cry;
}
var crow = {
  name : "カラス",
  cry : "カーカー",
  sing : function(d) {d.textContent = this.name + "が" + this.cry;}
};
$.proxy(bird, crow, d01)();    // 戻り値である関数オブジェクトを実行する
$.proxy(crow, "sing", d02)();
</script>

また、上の例の jQuery の記述部分は jQuery を使用しなければ、次のように書き換えることもできます。

function slice(args, s) {
  let n = args.length - s;
  let array = new Array(n);
  for (let i = 0; i < n; i++) {
   array[i] = args[i + s];
  }
  return array;
}
function proxy1(func, context) {
 let args = slice(arguments, 2);    // 残余引数を取り出す
  return function() {func.apply(context, args);};
}
function proxy2(context, name) {
  let args = slice(arguments, 2);    // 残余引数を取り出す
  return function() {context[name].apply(context, args);};
}

proxy1(bird, crow, d01)();    // 戻り値である関数オブジェクトを実行する
proxy2(crow, "sing", d02)();
</script>
実行例(jQuery 使用)
実行例(jQuery 未使用)

(3-2)空の関数

別のある関数に対してコールバック関数を引数として渡さなければいけないようなケースで コールバック関数で特に何もする必要がない場合に使用します。

メソッド引数機能戻り値
$.noop()なし何もしない関数を返す関数
記述例
<span id="d01"></span><br>
<div class="switch" onclick="exec();">今の時刻</div><br>
<script>
function exec() {
  let now = new Date();
  d01.textContent = now.toLocaleString();   // exec 関数を何もしないようにする
  exec = $.noop();
}
</script>

また、上の例の jQuery の記述部分は jQuery を使用しなければ、次のように書き換えることもできます。

function exec() {
  let now = new Date();
  d01.textContent = now.toLocaleString();   // exec 関数を何もしないようにする
  exec = noop();
}

function noop() {
  return function() {};
}

「今の時刻」のボタンをクリックしてください。一度だけ時刻が表示されます。

実行例(jQuery 使用)
実行例(jQuery 未使用)

(4)その他

(4-1)Javascript の実行

メソッド引数機能戻り値
$.globalEval(コード)コード:Javascript の命令Javascript の命令を、グローバル空間で実行するなし

eval メソッドも文字列をスクリプトとして実行しますが、あくまでもその場所でスクリプトを実行するだけです。したがって、次の例のような変数定義はローカル変数の定義となり、関数外からの参照はできません。

記述例
<span id="d01"></span><br>
<span id="d02"></span><br>
<script>
function setup(){
  $.globalEval("var global = 10;");
  eval("var local = 20;");           // ローカル変数の定義になる
}
setup();

d01.textContent = global;
try {
  d02.textContent = local;
}
catch(e) {
  d02.textContent = e;
}
</script>

また、上の例の jQuery の記述部分は jQuery を使用しなければ、次のように書き換えることもできます。

function setup(){
  globalEval("var global = 10;");
  eval("var local = 20;");           // ローカル変数の定義になる
}
setup();

function globalEval(code) {
  let script = document.createElement("script");
  script.text = code;
  document.head.appendChild(script).parentNode.removeChild(script);
}

// 以下略

実行例(jQuery 使用)
実行例(jQuery 未使用)

(4-2)DOMオブジェクトに変換

メソッド引数機能戻り値
$.parseHTML(HTML [,スクリプト])HTML:解析するHTML文字列
スクリプト:true のときは script 要素を含む(規定値:false)
HTML文字列をDOMノードの配列に変換するDOMノードの配列
$.parseJSON(JSON)JSON:解析するJSON文字列JSON文字列をオブジェクトに変換する(注)オブジェクト
$.parseXML(XML)XML:解析するXML文字列XML文字列をXMLオブジェクトに変換するXMLオブジェクト
注)JSON文字列プロパティ名は "(ダブルクォーテーション)で囲む必要がある

2つ目の parseHTML の1つ目の引数には script 要素が含まれています。2つ目の引数に true を指定すると、戻り値にも script 要素が含まれますが、指定しないと戻り値に script 要素は含まれません。

なお、Javascript が <!-- //--> で囲ってあるのは、文字列中に現れる <script> </script> を実際のスクリプト要素と解釈されないようにするためです。

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

<script>
<!--
d01.innerHTML = dispHTML($.parseHTML("normal1<b>bold</b>normal2<i>italic</i>"));
var html = "text<script>alert('xx');</script>";
d11.innerHTML = dispHTML($.parseHTML(html));
d12.innerHTML = dispHTML($.parseHTML(html, true));
var json = '{"name":"Taro", "age":20}';    // クオーテーションに注意
d21.innerHTML = dispJSON($.parseJSON(json));
var xml = $.parseXML("<xml><name>Taro</name><age>20</age></xml>");
d31.textContent = xml.getElementsByTagName("name")[0].textContent;
d32.textContent = xml.getElementsByTagName("age")[0].textContent;

function dispHTML(dom) {
  let s = "";
  for (let i = 0 ; i <dom.length ; i++) {
    let t = dom[i].nodeType;
    let c = "";
    if (t == 1)       // ELEMENT_NODE
      c = dom[i].outerHTML.replace(/</g, "<").replace(/>/g, ">");
    else if (t == 3)  // TEXT_NODE
      c = dom[i].textContent;
    s += c + "<br>";
  }
  return s;
}

function dispJSON(obj) {
  let s = "";
  let k = Object.keys(obj);
  for (let i in k) {
    s += k[i] + ":" + obj[k[i]] + "<br>";
  }
  return s;
}
// -->
</script>

また、上の例の jQuery の記述部分は jQuery を使用しなければ、次のように書き換えることもできます。

d01.innerHTML = dispHTML(parseHTML("normal1<b>bold</b>normal2<i>italic</i>"));
var html = "text<script>alert('xx');</script>";
d11.innerHTML = dispHTML(parseHTML(html));
d12.innerHTML = dispHTML(parseHTML(html, true));
var json = '{"name":"Taro", "age":20}';
d21.innerHTML = dispJSON(parseJSON(json));
var xml = parseXML("<xml><name>Taro</name><age>20</age></xml>");
d31.textContent = xml.getElementsByTagName("name")[0].textContent;
d32.textContent = xml.getElementsByTagName("age")[0].textContent;

function parseHTML(html, keepScripts) {
  let div = document.createElement('div');
  div.style.display = 'none';
  div.innerHTML = keepScripts ? html : html.replace(/<script>.*<\/script>/g, '');
  return div.childNodes;
}
function parseJSON(json) {
  return JSON.parse(json);
}
function parseXML(xml) {
  let parser = new DOMParser();
  return parser.parseFromString(xml, 'text/xml');
}

// 以下略

実行例(jQuery 使用)
実行例(jQuery 未使用)

(4-3)クラス

メソッド引数機能戻り値
$.type(オブジェクト)オブジェクト:クラス(的なものの)名を取得したいオブジェクトJavaScriptのオブジェクトの型を返すオブジェクトの型名

記述例
<span id="d01"></span><br>

<!-- 以下略 -->

<script>
d01.textContent = $.type(true);
d02.textContent = $.type(new Boolean());
d03.textContent = $.type(5);
d04.textContent = $.type(new Number(5));
d05.textContent = $.type("string");
d06.textContent = $.type(new String("string"));
d07.textContent = $.type(function(){});
d08.textContent = $.type([]);
d09.textContent = $.type(new Array());
d10.textContent = $.type(new Error());
d11.textContent = $.type(/xxx/);
</script>

また、上の例の jQuery の記述部分は jQuery を使用しなければ、次のように書き換えることもできます。

d01.textContent = type(true);
d02.textContent = type(new Boolean());
d03.textContent = type(5);
d04.textContent = type(new Number(5));
d05.textContent = type("string");
d06.textContent = type(new String("string"));
d07.textContent = type(function(){});
d08.textContent = type([]);
d09.textContent = type(new Array());
d10.textContent = type(new Error());
d11.textContent = type(/xxx/);

function type(obj) {
  let str = Object.prototype.toString.call(obj);
  let name = str.match(/(?<=\[object ).*(?=\])/).toString();
  return name.toLowerCase();
}
実行例(jQuery 使用)
実行例(jQuery 未使用)

(4-4)ブラウザ

プロパティ
supportR/Oブラウザがサポートしているか否かの情報
Key説明
ajaxブラウザが XMLHttpRequest を生成できれば true
checkClonedocument fragmentsにて、ブラウザが radio要素、checkbox要素のチェック状態を正確に複製できれば true
checkOncheckbox 要素に value が指定されていないとき、'on'が自動的に割り当てられる場合は true
corsブラウザが XMLHttpRequest を生成でき、そのオブジェクトが withCredentials プロパティを持っていれば true
noCloneChecked複製したDOM要素が checked(展開?)の状態までコピーすれば true
optSelectedデフォルトで選択されている option要素の、selectedプロパティが機能している場合は true

記述例
<span id="d01"></span><br>

<!-- 以下略 -->

<script>
var support = $.support;
d01.textContent = support.ajax;

d04.textContent = support.checkClone;
d05.textContent = support.checkOn;
d06.textContent = support.cors;

d11.textContent = support.noCloneChecked;

d15.textContent = support.optSelected;

</script>
実行例

(4-5)その他

○ now

メソッド引数機能戻り値
$.now()なし時間(ミリ秒)を取得する1970年1月1日0時0分0秒から経過した時間(ミリ秒)

記述例
<span id="d01"></span><br>
<span id="d02"></span><br>
<script>
var n = $.now();
d01.textContent = n;
var dt = new Date(n);
d02.textContent = dt.toLocaleString() + "." + ("00" + dt.getUTCMilliseconds()).substr(-3);
</script>

また、上の例の jQuery の記述部分は jQuery を使用しなければ、次のように書き換えることもできます。

var dt = new Date();
d01.textContent = dt.getTime();
d02.textContent = dt.toLocaleString() + "." + ("00" + dt.getUTCMilliseconds()).substr(-3);
実行例(jQuery 使用)
実行例(jQuery 未使用)

○ trim

メソッド引数機能戻り値
$.trim(文字列)文字列:対象の文字列先頭と末尾の全ての改行・空白(ノーブレークスペースも含む)・タブを除去する空白が除去された文字列

記述例
<span id="d01"></span><br>

<!-- 以下略 -->

<script>
d01.textContent = "|" + $.trim("  AAA BBB   ") + "|";
d02.textContent = "|" + $.trim("  AAA BBB  ") + "|";
d03.textContent = "|" + $.trim("\t\tAAA\tBBB\t\t\t") + "|";
d04.textContent = "|" + $.trim("\n\nAAA\nBBB\n\n") + "|";
</script>

また、上の例の jQuery の記述部分は jQuery を使用しなければ、次のように書き換えることもできます。

d01.textContent = "|" + "  AAA BBB   ".trim() + "|";
d02.textContent = "|" + "  AAA BBB  ".trim() + "|";
d03.textContent = "|" + "\t\tAAA\tBBB\t\t\t".trim() + "|";
d04.textContent = "|" + "\n\nAAA\nBBB\n\n".trim() + "|";
実行例(jQuery 使用)
実行例(jQuery 未使用)

13.3.14  Ajax

Ajaxとは「Asynchronous JavaScript + XML」の略です。簡単に言えば JavaScript と XML を使って非同期にサーバとの間の通信を行うための方法です。

Ajax を使用することで画面遷移をせずに HTML を更新することが可能なので、ユーザビリティの向上やサーバ負荷の軽減に繋がります。

(1)簡易メソッド

シンプルな記述で簡単に外部データの読込が行えるメソッドです。詳細を設定したい場合は低レベル・インターフェスのメソッドを利用して下さい。

(1-1)load

サーバーからhtmlコンテンツを取得してセレクタの要素に表示します。

メソッド引数機能戻り値
load(URL[,関数])URL:取得データのURL(セレクタも記述できる)
関数:リクエストが完了した際に実行したい関数
サーバーから html コンテンツを取得してセレクタの要素に表示するjQuery オブジェクト
load(URL,データ[,関数])URL:CGIのURL
データ:送信する文字列またはオブジェクト(注)
関数:リクエストが完了した際に実行したい関数
サーバーにデータを送り、その結果を取得してセレクタの要素に表示するjQuery オブジェクト
注)文字列の場合は GET、オブジェクトの場合は POST で HTTP通信を行う。
関数の形式
function(受信データ, 状態, jqXHR)
 受信データ: load の引数で指定した「データ」と同じ
 状態: 読込みの成否
状態意味
success成功
error失敗
notmodified更新されていない
timeoutタイムアウト
parsererrorパーサーエラー(構文エラー)
 jqXHR: jqXHR オブジェクト(jqXHR.status は HTTP のステータスコード、jqXHR.statusText にはその意味)
記述例
<span id="d10"></span><br>

<!-- 以下略 -->

<script>
$("#d10").load("sample.txt");
$("#d20").load("sample.htm");
$("#d30").load("sample.htm #b");
$("#d40").load("sample.htm :even");
$("#d50").load("sample.htm", function(data, status, jqXHR) {d51.textContent=status + "(" + jqXHR.status + " " + jqXHR.statusText + ")";});
</script>
sample.txt
AAA
BBBBB
C
sample.htm
<span id="a">AAA</span>
<span id="b" style="color:red;">BBBBB</span>
<span id="c">C</span>

また、上の例の jQuery の記述部分は jQuery を使用しなければ、次のように書き換えることもできます。

なお、[].slice.call は Array.prototype.slice.call と書くこともでき、querySelectorAll などの戻り値を Array オブジェクトに変換します。

function load(url, filter, callback) {
  let xhr = new XMLHttpRequest();  // HTTPでファイルを読み込むためのXMLHttpRxhruestオブジェクトを生成
  xhr.open("GET", url, false); // 同期通信
  xhr.send("");
  let s = xhr.responseText;
  if (filter != undefined && filter != "") {
    let temp = document.createElement("span");
    temp.innerHTML = s;
    let e = [].slice.call(temp.querySelectorAll(filter));
    temp.innerHTML = "";
    e.forEach(function(e) {temp.appendChild(e);});
    s = temp.innerHTML;
  }
  if (typeof callback === "function")
    callback(s, xhr.status = 200 ? "success" : "error", xhr);
  return s;
}

d10.innerHTML = load("sample.txt");
d20.innerHTML = load("sample.htm");
d30.innerHTML = load("sample.htm", "#b");
d40.innerHTML = load("sample.htm", ":nth-child(odd)");
d50.innerHTML = load("sample.htm", "", function(data, status, xhr) {d51.textContent=status + "(" + xhr.status + " " + xhr.statusText + ")";});
実行例(jQuery 使用)
実行例(jQuery 未使用)

記述例
<span id="d1"></span><br>
<span id="d2"></span><br>

<script>
$("#d1").load("get.cgi", "name=太郎&gender=male&fruits=みかん");
$("#d1").load("post.cgi", {name:"花子", gender:"female", fruits:"パイナップル"});
</script>

また、上の例の jQuery の記述部分は jQuery を使用しなければ、次のように書き換えることもできます。

function load(url, data) {
  let xhr = new XMLHttpRequest();  // データを送信するためのXMLHttpRxhruestオブジェクトを生成
  if (typeof data === "string") {
    xhr.open('GET', url + "?" + data, false);
    xhr.send(null);
  }
  else {
    xhr.open('POST', url, false);
    xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
    xhr.send(encodeHTMLForm(data));
  }
  return xhr.responseText;
}

// HTMLフォームの形式にデータを変換する
function encodeHTMLForm(data)
{
  let params = [];
  for(let name in data) {
    let value = data[name];
    let param = encodeURIComponent(name) + "=" + encodeURIComponent(value);
    params.push(param);
  }
  return params.join("&").replace(/%20/g, "+");
}

d1.innerHTML = load("get1.cgi", "name=太郎&gender=male&fruits=みかん");
d2.innerHTML = load("post1.cgi", {name:"花子", gender:"female", fruits:"パイナップル"});

「太郎」さんは「男性」で「みかん」が、「花子」さんは「女性」で「パイナップル」が好きだと送っています。実行例はそれに対する返答です。

実行例(jQuery 使用)
実行例(jQuery 未使用)


(1-2)get、getJSON、getScript

GET による Ajax 通信を行います。

メソッド引数機能戻り値
$.get(URL[,関数][,データタイプ])URL:データのURL
関数:リクエストが成功した際に実行したい関数
データタイプ:サーバから返されるデータ方式
xml、json、script、text、html(省略してもある程度判断される)
URL で指定したデータを HTTP リクエスト(GETメソッド)を使用して送るjqXHR オブジェクト
$.getJSON(URL[,関数])データタイプ="json" の get と同じ)URL:データのURL
関数:リクエストが成功した際に実行したい関数
URL で指定したデータを HTTP リクエスト(GETメソッド)を使用して送るjqXHR オブジェクト
$.getScript(URL[,関数])データタイプ="script" の get と同じ)URL:データのURL
関数:リクエストが成功した際に実行したい関数
URL で指定したデータを HTTP リクエスト(GETメソッド)を使用して送るjqXHR オブジェクト
$.get(URL,データ[,関数][,データタイプ])URL:CGIのURL
データ:送信するオブジェクト
関数:リクエストが成功した際に実行したい関数
データタイプ:サーバから返されるデータ方式
xml、json、script、text、html(省略してもある程度判断される)
リクエスト先の URL にデータを HTTP リクエスト(GETメソッド)を使用して送るjqXHR オブジェクト
関数の形式
function(受信データ, 状態, jqXHR)
 受信データ: load の引数で指定した「データ」と同じ
 状態: 読込みの成否
状態意味
success成功
error失敗
notmodified更新されていない
timeoutタイムアウト
parsererrorパーサーエラー(構文エラー)
 jqXHR: jqXHR オブジェクト(jqXHR.status は HTTP のステータスコード、jqXHR.statusText にはその意味)

データタイプを指定しなくても url で指定したファイルの内容に合わせて正しく読み込みます。

3つ目と4つ目の例は、同じファイルを指定していますが、データタイプを text と指定した4つ目の例は、記述したそのままを文字列で関数に引き渡しています。

記述例
<span id="d10"></span><br>
<span id="d20"></span> <span id="d21"></span><br>

<!-- 以下略 -->

<script>
$.get("sample.htm", function(data) {d10.innerHTML=data;});
$.get("sample.xml", function(data) {d20.textContent=data; d21.textContent=data.getElementsByTagName("b")[0].innerHTML;});
$.get("sample.json", function(data) {d30.textContent=data; d31.textContent=data.b;});
$.get("sample.json", function(data) {d40.textContent=data;}, "text");
$.get("sample.js", function(data) {d50.textContent=data;test(d51, "BBBBB");}, "script");
$.getJSON("sample.json", function(data) {d60.textContent=data; d61.textContent=data.b;});
$.getScript("sample.js", function(data) {d70.textContent=data;test(d71, "BBBBB");}, "script");
</script>
sample.htm
<span id="a">AAA</span>
<span id="b" style="color:red;">BBBBB</span>
<span id="c">C</span>
sample.xml
<xml>
<a>AAA</a>
<b>BBBBB</b>
<c>C</c>
</xml>
sample.json
{
  "a": "AAA",
  "b": "BBBBB",
  "c": "C"
}
sample.js
function test(e, m){e.innerText = m;}

また、上の例の jQuery の記述部分は jQuery を使用しなければ、次のように書き換えることもできます。

ただし、引数は省略できません。また、エラー処理はほとんどしていません。

function read(url) {
  let xhr = new XMLHttpRequest();  // HTTPでファイルを読み込むためのXMLHttpRrequestオブジェクトを生成
  xhr.open("GET", url, false); // 同期通信
  xhr.send("");
  return xhr;
}
function get(url, callback, type) {
  let xhr = read(url);
  if (xhr.status != 200) {
    callback("", "error", xhr);
    return;
  }
  let s = xhr.responseText;

  if (type == "html") {
    let parser = new DOMParser();
    let doc = parser.parseFromString(s, "text/" + type);
    callback(doc.body.innerHTML, "success", xhr);
  }
  else if (type == "xml") {
    let parser = new DOMParser();
    let doc = parser.parseFromString(s, "text/" + type);
    callback(doc, "success", xhr);
  }
  else if (type == "json") {
    let doc = JSON.parse(s);
    callback(doc, "success", xhr);
  }
  else if (type == "text") {
    callback(s, "success", xhr);
  }
  else if (type == "script") {
    let script = document.createElement("script");
    script.text = s;
    document.head.appendChild(script);
    callback(s, "success", xhr);
    document.head.removeChild(script);
  }
}
function getJSON(url, callback) {
  let xhr = read(url);
  if (xhr.status != 200) {
    callback("", "error", xhr);
    return null;
  }
  let s = JSON.parse(xhr.responseText);
  callback(s, "success", xhr);
}
function getScript(url, callback) {
  let xhr = read(url);
  if (xhr.status != 200) {
    callback("", "error", xhr);
    return null;
  }
  let s = xhr.responseText;
  let script = document.createElement("script");
  script.text = s;
  document.head.appendChild(script);
  callback(s, "success", xhr);
  document.head.removeChild(script);
}

get("sample.htm", function(data) {d10.innerHTML=data;}, "html");
get("sample.xml", function(data) {d20.textContent=data; d21.textContent=data.getElementsByTagName("b")[0].innerHTML;}, "xml");
get("sample.json", function(data) {d30.textContent=data; d31.textContent=data.b;}, "json");
get("sample.json", function(data) {d40.textContent=data;}, "text");
get("sample.js", function(data) {d50.textContent=data;test(d51, "BBBBB");}, "script");
getJSON("sample.json", function(data) {d60.textContent=data; d61.textContent=data.b;});
getScript("sample.js", function(data) {d70.textContent=data;test(d71, "BBBBB");});
実行例(jQuery 使用)
実行例(jQuery 未使用)

データとしてオブジェクトを指定した場合にも、URLエンコードが施されたURLクエリーの文字列に変換され、サーバーには送信されます。つまり、2つ目の例もサーバーへは1つ目の例と全く同じ形式でデータが送られるわけです。

4つ目と5つ目の例は、サーバーから同じデータが送られて来ますが、データタイプを変えることによって受け取る形式が変わることを示しています。

記述例
<span id="d10"></span><br>
<span id="d20"></span><br>

<!-- 以下略 -->

<script>
$.get("get1.cgi", "a=AAA&b=BBBBBB&c=C", function(data) {d10.innerHTML=data;});
$.get("get1.cgi", {a:'AAA',b:'BBBBBB',c:'C'}, function(data) {d20.innerHTML=data;});
$.get("get2.cgi", {a:'AAA',b:'BBBBBB',c:'C'}, 
                       function(data) {d30.textContent=data; d31.textContent=data.getElementsByTagName("b")[0].innerHTML;}, "xml");
$.get("get3.cgi", {a:'AAA',b:'BBBBBB',c:'C'},
                       function(data) {d40.textContent=data; d41.textContent=data.b;}, "json");
$.get("get3.cgi", {a:'AAA',b:'BBBBBB',c:'C'}, function(data) {d50.textContent=data;}, "text");
</script>

また、上の例の jQuery の記述部分は jQuery を使用しなければ、次のように書き換えることもできます。

ただし、script には対応していません。また、エラー処理はほとんどしていません。

function get(url, data, callback, type) {
  let xhr = new XMLHttpRequest();  // HTTPでファイルを読み込むためのXMLHttpRrequestオブジェクトを生成
  let param = (typeof data === "object") ? encodeHTMLForm(data) : data;
  xhr.open("GET", url + "?" + param, false); // 同期通信
  xhr.send();
  if (xhr.status != 200) {
    callback("", "error", xhr);
    return;
  }
  let ret;
  switch(type) {
   case "xml" :
    let parser = new DOMParser();
    ret = parser.parseFromString(xhr.responseText, "text/xml");
    break;
   case "json" :
    ret = JSON.parse(xhr.responseText);
    break;
   default :
    ret = xhr.responseText;
    break;
  }
  callback(ret, "success", xhr);
}

// HTMLフォームの形式にデータを変換する
function encodeHTMLForm(data)
{
  let params = [];
  for(let name in data) {
    let value = data[name];
    let param = encodeURIComponent(name) + "=" + encodeURIComponent(value);
    params.push(param);
  }
  return params.join("&").replace(/%20/g, "+");
}

get("get1.cgi", "a=AAA&b=BBBBBB&c=C", function(data) {d10.innerHTML=data;});
get("get1.cgi", {a:'AAA',b:'BBBBBB',c:'C'}, function(data) {d20.innerHTML=data;});
get("get2.cgi", {a:'AAA',b:'BBBBBB',c:'C'}, 
                     function(data) {d30.textContent=data; d31.textContent=data.getElementsByTagName("b")[0].innerHTML;}, "xml");
get("get3.cgi", {a:'AAA',b:'BBBBBB',c:'C'},
                     function(data) {d40.textContent=data; d41.textContent=data.b;}, "json");
get("get3.cgi", {a:'AAA',b:'BBBBBB',c:'C'}, function(data) {d50.textContent=data;}, "text");
実行例(jQuery 使用)
実行例(jQuery 未使用)

(1-3)post

POST による Ajax 通信を行います。

メソッド引数機能戻り値
$.post(URL,データ[,関数][,データタイプ])URL:CGIのURL
データ:送信するオブジェクト
関数:リクエストが成功した際に実行したい関数
関数の形式
function(受信データ, 状態, jqXHR)
 受信データ: load の引数で指定した「データ」と同じ
 状態: 読込みの成否
状態意味
success成功
error失敗
notmodified更新されていない
timeoutタイムアウト
parsererrorパーサーエラー(構文エラー)
 jqXHR: jqXHR オブジェクト
データタイプ:サーバから返されるデータ方式
xml、json、script、text、html(省略してもある程度判断される)
リクエスト先の URL にデータを HTTP リクエスト(POSTメソッド)を使用して送るjqXHR オブジェクト

データとしてオブジェクトを指定した場合にも、URLエンコードが施されたURLクエリーの文字列に変換され、サーバーには送信されます。つまり、2つ目の例もサーバーへは1つ目の例と全く同じ形式でデータが送られるわけです。

4つ目と5つ目の例は、サーバーから同じデータが送られて来ますが、データタイプを変えることによって受け取る形式が変わることを示しています。

記述例
<span id="d10"></span><br>
<span id="d20"></span><br>

<!-- 以下略 -->

<script>
$.post("post1.cgi", "a=AAA&b=BBBBBB&c=C", function(data) {d10.innerHTML=data;});
$.post("post1.cgi", {a:'AAA',b:'BBBBBB',c:'C'}, function(data) {d20.innerHTML=data;});
$.post("post2.cgi", {a:'AAA',b:'BBBBBB',c:'C'}, 
                         function(data) {d30.textContent=data; d31.textContent=data.postElementsByTagName("b")[0].innerHTML;}, "xml");
$.post("post3.cgi", {a:'AAA',b:'BBBBBB',c:'C'}, function(data) {d40.textContent=data; d41.textContent=data.b;}, "json");
$.post("post3.cgi", {a:'AAA',b:'BBBBBB',c:'C'}, function(data) {d50.textContent=data;}, "text");
</script>

また、上の例の jQuery の記述部分は jQuery を使用しなければ、次のように書き換えることもできます。

ただし、script には対応していません。また、エラー処理はほとんどしていません。

function post(url, data, callback, type) {
  let xhr = new XMLHttpRequest();  // HTTPでファイルを読み込むためのXMLHttpRequestオブジェクトを生成
  let param = (typeof data === "object") ? encodeHTMLForm(data) : data;
  xhr.open("POST", url, false);
  xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
  xhr.send(param);
  if (xhr.status != 200) {
    callback("", "error", xhr);
    return;
  }
  let ret;
  switch(type) {
   case "xml" :
    let parser = new DOMParser();
    ret = parser.parseFromString(xhr.responseText, "text/xml");
    break;
   case "json" :
    ret = JSON.parse(xhr.responseText);
    break;
   default :
    ret = xhr.responseText;
    break;
  }
  callback(ret, "success", xhr);
}

// HTMLフォームの形式にデータを変換する
function encodeHTMLForm(data)
{
  let params = [];
  for(let name in data) {
    let value = data[name];
    let param = encodeURIComponent(name) + "=" + encodeURIComponent(value);
    params.push(param);
  }
  return params.join("&").replace(/%20/g, "+");
}

post("post1.cgi", "a=AAA&b=BBBBBB&c=C", function(data) {d10.innerHTML=data;});
post("post1.cgi", {a:'AAA',b:'BBBBBB',c:'C'}, function(data) {d20.innerHTML=data;});
post("post2.cgi", {a:'AAA',b:'BBBBBB',c:'C'}, 
                       function(data) {d30.textContent=data; d31.textContent=data.getElementsByTagName("b")[0].innerHTML;}, "xml");
post("post3.cgi", {a:'AAA',b:'BBBBBB',c:'C'}, function(data) {d40.textContent=data; d41.textContent=data.b;}, "json");
post("post3.cgi", {a:'AAA',b:'BBBBBB',c:'C'}, function(data) {d50.textContent=data;}, "text");
実行例(jQuery 使用)
実行例(jQuery 未使用)

(2)グローバルイベントハンドラ

初期化や完了などの特定のイベントが発生したとき呼び出されるイベントハンドラを登録します。

なお、グローバル・イベントは、globalin jQuery.ajaxSetup() が true のとき Ajax リクエストごとに発生します。

メソッド引数機能戻り値
ajaxComplete(関数)関数:イベントが発生したときに実行したい関数Ajaxリクエストが完了したときの処理を設定するjQuery オブジェクト
ajaxError(関数)関数:イベントが発生したときに実行したい関数Ajaxリクエストが失敗したときの処理を設定するjQuery オブジェクト
ajaxSend(関数)関数:イベントが発生したときに実行したい関数Ajaxリクエストが送信されたときの処理を設定するjQuery オブジェクト
ajaxStart(関数)関数:イベントが発生したときに実行したい関数Ajaxリクエストが送信されようとしているときの処理を設定するjQuery オブジェクト
ajaxStop(関数)関数:イベントが発生したときに実行したい関数Ajaxリクエストの完了時、未処理のAjaxリクエストが無いときの処理を設定するjQuery オブジェクト
ajaxSuccess(関数)関数:イベントが発生したときに実行したい関数Ajaxリクエストが成功したときの処理を設定するjQuery オブジェクト
関数の形式
function(event, jqXHR, settings)
 event: イベントオブジェクト
 jqXHR: jqXHR オブジェクト(jqXHR.status は HTTP のステータスコード、jqXHR.statusText にはその意味)
 settings: ajax通信に関する設定情報を持ったオブジェクト

イベントが発生した順番にそのイベント名を表示しています。

記述例
<span id="d00"></span><span id="d01"></span><span id="d02"></span><br>

<!-- 以下略 -->

<script>
var m = 0;
$(document).ajaxComplete(set);
$(document).ajaxSend(set);
$(document).ajaxStart(set);
$(document).ajaxStop(set);
$(document).ajaxSuccess(set);
$(document).ajaxError(set);

$(function() {m = 0; $("#d").load("sample.txt"); $.holdReady(false);});

function set(event, jqXHR) {
  document.getElementById("d" + m + 0).textContent=event.type;
  document.getElementById("d" + m + 1).textContent=jqXHR != undefined ? jqXHR.status : "";
  m++;
}
</script>

また、上の例の jQuery の記述部分は jQuery を使用しなければ、次のように書き換えることもできます。

ただし、ajaxStop に対応するイベントは記述していません。

var xhr = new XMLHttpRequest();
xhr.addEventListener("loadend", loadend(xhr), false);
xhr.addEventListener("readystatechange", readystatechange(xhr), false);
xhr.open("GET", "sample.txt");
xhr.send("");
function loadend(xhr) {
  return function(event) {
    set({type:"Complete"}, xhr);
  }
}
function readystatechange(xhr) {
  return function(event) {
    if (xhr.readyState == XMLHttpRequest.OPENED) {
      set({type:"Start"});
    }
    else if (xhr.readyState == XMLHttpRequest.HEADERS_RECEIVED) {
      set({type:"Send"});
    }
    else if (xhr.readyState == XMLHttpRequest.DONE) {
      if (xhr.status == 200) {
        set({type:"Success"}, xhr);
      }
      else {
        set({type:"Error"}, xhr);
      }
    }
  }
}

左側は正常に終了した場合で、右側はエラーが起きた(ファイルが存在しなかった)場合です。

実行例(jQuery 使用)
実行例(jQuery 未使用)

(3)低レベル・インターフェイス

Ajax 通信を行うためのメソッドと初期設定を変更するためのメソッドです。

(3-1)ajax

Ajax 通信を行います。

サーバーからデータを取得するために利用しますが、引数の settings に設定する Object オブジェクトを利用して、非常に詳細な設定をすることができます。ただし、大抵の場合、$.get で充分です。$.ajax から複雑な詳細設定を省き、簡単に利用できるようにしたのが $.get です。

メソッド引数機能戻り値
$.ajax([URL][, settings])URL:Ajaxリクエストを送信するURL(settings 内の url と同じ)
settings:Ajaxリクエストの詳細設定
Ajaxリクエストを送信するjqXHR オブジェクト
settings の形式
キー初期値意味
acceptsObjectDataTypeに依存サーバから返されるデータ方式
asyncBooleantruetrue:非同期、false:同期(非推奨)
beforeSend関数(1)なしAjax送信前に実行したいメソッド(送信ヘッダーの変更などが可能)false を返すとAjax送信を中止する
cacheBooleantrue(dataTypeがscript
またはjsonpの場合は、false)
true:ページをキャッシュする、false:キャッシュしない
complete関数、関数の配列(2)なしリクエストが完了した際に呼び出されるメソッド
contentsObjectなしコンテンツタイプに応じて、どのようにパースするかを指定する文字列/正規表現のペア
contentTypeStringapplication/x-www-form-urlencoded; charset=UTF-8サーバーへデータが送信されるときに使用されるコンテンツタイプ
contextObjectなしcomplete などで指定した関数内で参照する this の値
convertersObject{"* text": window.String, "text html": true,
"text json": jQuery.parseJSON, "text xml": jQuery.parseXML}
データタイプごとのコンバーター
(初期値は jsonはjQuery.parseJSON、xmlはjQuery.parseXML)
crossDomainBooleanクロス(別の)ドメインのとき true
同じドメインのとき false
強制的にクロスドメインでリクエストしたい場合に true にする
dataObject または Stringなしサーバーに渡したいデータ
dataFilter関数(3)なしサーバから受信したデータのフィルタリング
dataTypeStringxml,json,script,html から判断サーバーから返されるデータの型
データの型意味
xmlXMLドキュメント
htmlプレーンテキストとしてのHTML
scriptJavaScriptとしてレスポンスを実行し、プレーンテキストとしてその結果を返す
jsonJavaScriptオブジェクト
jsonpJSONPを使用してJSONブロックを読み込む
textプレーンテキスト
なお、これらを空白区切りで複数指定できます
error関数、関数の配列(4)なし通信が失敗した時に実行したいメソッド
globalBooleantrueグローバルイベントハンドラを実行するかどうか
headersObject{}(空のオブジェクト)追加のヘッダ情報
ifModifiedBooleanfalsetrue:更新されている場合のみ受信、false:常に受信
isLocalBoolean(現在のローカルのプロトコルに依存)true:サーバー上でもローカルと認識、false:常に受信
jsonpStringなしjsonpリクエストのコールバック関数
jsonpCallbackString または関数なしJSONPリクエストのためのコールバック関数
mimeTypeStringなしXHRのMIME タイプをオーバーライドする
passwordStringなしHTTPアクセスの認証リクエストに応答するXMLHttpRequestに使用されるパスワード
processDataBooleantruetrue:content-typeをapplication/x-www-form-urlencoded で変換、false:変換しない
scriptCharsetStringなしgetでデータタイプが「jsonp」か「script」の場合のcharset属性
statusCodeObject{}ステータスコードとそれに対応する関数
{
  ステータスコード:関数
  ステータスコード:関数
}(5)
success関数(5)なし通信が成功した時に実行する関数
timeout数値なしタイムアウトの時間(ミリ秒)
traditionalBooleanfalsetrue:v1.4以前の形式でシリアライズ(送受信用の形式に)するparam 参照
typeString"GET"リクエストのタイプ("POST"または"GET")
urlString現在のページリクエストを送信するURL(第一引数に指定するのと同じ)
usernameStringなしHTTPアクセスの認証リクエストに応答するXMLHttpRequestに使用されるユーザー名
xhr関数XMLHttpRequest(IEはActiveXObject)XMLHttpRequestオブジェクトが生成された際のコールバック関数
xhrFieldsObject{}ネイティブのXHRオブジェクト上に設定する、フィールド名/フィールド値のペアのオブジェクト
関数の形式
(1)function(jqXHR, 詳細設定)
  jqXHR: jqXHR オブジェクト(jqXHR.status は HTTP のステータスコード、jqXHR.statusText にはその意味)
  詳細設定: Ajaxリクエストの詳細設定
(2)function(jqXHR, 状態)
  jqXHR: jqXHR オブジェクト(jqXHR.status は HTTP のステータスコード、jqXHR.statusText にはその意味)
  状態: 読込みの成否
状態意味
success成功
error失敗
notmodified更新されていない
timeoutタイムアウト
parsererrorパーサーエラー(構文エラー)
abortアボート
(3)function(データ, タイプ)
  データ: サーバーから受信したデータ
  タイプ: データの形式(dataType 参照)
(4)function(jqXHR, 状態, 例外情報)
  jqXHR: jqXHR オブジェクト(jqXHR.status は HTTP のステータスコード、jqXHR.statusText にはその意味)
  状態: 読込みの成否
状態意味
error失敗
timeoutタイムアウト
parsererrorパーサーエラー(構文エラー)
abortアボート
  例外情報: HTTPステータス
(5)function(データ, 状態, jqXHR)
  データ: 受信内容
  状態: 読込みの成否
状態意味
success成功
error失敗
notmodified更新されていない
timeoutタイムアウト
parsererrorパーサーエラー(構文エラー)
abortアボート
  jqXHR: jqXHR オブジェクト(jqXHR.status は HTTP のステータスコード、jqXHR.statusText にはその意味)

すべての settings の例は挙げられないので、ほんの一部だけ指定しています。

beforeSend は送信前に実行する関数を指定しますが、この関数内で送信データを変更しても送られるデータは変更前の "BBBBB" のようです。

記述例
<span id="d10"></span><span id="d11"></span><br>

<!-- 以下略 -->

<script>
var d = {a:"AAA",b:"BBBBB",c:"C"};
$.ajax("get.cgi", {
  type:'GET',
  dataType:'text',
  data:d,           // 送信データ
  context:d,        // 関数内の this の設定
  beforeSend:function(jqXHR, settings) {
    d.b = "xxx";   // (注)ここで変えても送信データは変わらない
    settings.success = function(data, status, jqXHR) {d10.textContent = data; d11.textContent = status;},
  },
  complete:function(jqXHR, status) {d20.textContent = this.b; d21.textContent = jqXHR.status;}    // this は d
  statusCode:{
    200:function(data, status){d31.style.color = "blue"; d30.textContent = data; d31.textContent = status;},
    404:function(data, status){d31.style.color = "red"; d30.textContent = data; d31.textContent = status;},
  }
});
</script>

$.get を使用すると次のように記述できます。

ただし、d.b を送信前に "xxx" に変更しているので、送信データは BBBBB ではなく xxx になります。

var d = {a:"AAA",b:"BBBBB",c:"C"};
d.b = "xxx";
$.get("get.cgi", d, function(data, status, jqXHR) {d10.textContent = data; d11.textContent = status;}, "text")
  .always(function(data, status, jqXHR) {d20.textContent = d.b; d21.textContent = jqXHR.status;})
  .done(function(data, status, jqXHR) {d31.style.color = "blue"; d30.textContent = data; d31.textContent = status;})
  .fail(function(data, status, jqXHR) {d31.style.color = "red"; d30.textContent = data; d31.textContent = status;});

また、上の例の jQuery の記述部分は jQuery を使用しなければ、次のように書き換えることもできます。

ただし、d.b を送信前に "xxx" に変更しているので、送信データは BBBBB ではなく xxx になります。

var d = {a:"AAA",b:"BBBBB",c:"C"};
d.b = "xxx";
function get(url, data, type) {
  let xhr = new XMLHttpRequest();  // HTTPでファイルを読み込むためのXMLHttpRrequestオブジェクトを生成
  xhr.addEventListener("loadend", loadend(xhr), false);
  xhr.addEventListener("readystatechange", readystatechange(xhr), false);
  let param = (typeof data === "object") ? encodeHTMLForm(data) : data;
  xhr.open("GET", url + "?" + param, false); // 同期通信
  xhr.send();
}
function loadend(xhr) {
  return function(event) {
    d20.textContent = d.b; d21.textContent = xhr.status;
  }
}
function readystatechange(xhr) {
  return function(event) {
    if (xhr.readyState == XMLHttpRequest.DONE) {
      d20.textContent = xhr.responseText; d21.textContent = xhr.status;
      if (xhr.status == 200) {
        d10.textContent = xhr.responseText; d11.textContent = "success";
        d31.style.color = "blue"; d30.textContent = xhr.responseText; d31.textContent = "success";
      }
      else {
        d31.style.color = "red"; d30.textContent = xhr.responseText; d31.textContent = "error";
      }
    }
  }
}
// HTMLフォームの形式にデータを変換する
function encodeHTMLForm(data)
{
  let params = [];
  for(let name in data) {
    let value = data[name];
    let param = encodeURIComponent(name) + "=" + encodeURIComponent(value);
    params.push(param);
  }
  return params.join("&").replace(/%20/g, "+");
}

get("get.cgi", d, "text");
実行例(jQuery 使用)
実行例(jQuery 未使用)

(3-2)ajaxSetup

Ajax 通信に関連する設定のデフォルト値を変更します。

メソッド引数機能戻り値
$.ajaxSetup(settings)settings:Ajaxリクエストのデフォルト設定($.ajax を参照)ajax通信に関連するデフォルト値を変更するなし

デフォルト値を設定していますので、$.ajax() では何も設定していません。

そして、二つ目の $.ajax() ではデフォルト値とは異なる値を設定して実行しています。

記述例
<span id="d10"></span><span id="d11"></span><br>
<span id="d20"></span><span id="d21"></span><br>

<script>
var d = {a:"AAA",b:"BBBBB",c:"C"};
$.ajaxSetup({
  url:"get.cgi",
  type:'GET',
  dataType:'text',
  data:d,
  context:d,
  success:function(data, status, jqXHR) {d10.textContent = data; d11.textContent = status;}
});
$.ajax();     // デフォルト値で実行する
d.b = "bbb";
$.ajax({      // デフォルト値から一部変更して実行する
  data:d,
  success:function(data, status, jqXHR) {d20.textContent = data; d21.textContent = status;}
});
</script>
実行例

(3-3)ajaxPrefilter

Ajax通信によって送られるオプションを送信前に独自に制御します。また、タイプを指定することによって、変更するデータタイプを制限できます(指定したデータタイプのときだけ巻子が実行されます)。

メソッド引数機能戻り値
$.ajaxPrefilter([タイプ,] 関数)タイプ:text、html など関数を実行するデータ形式
関数:Ajax処理を制御する関数
Ajax 通信を行う前に設定を変更するなし
関数の形式
function(settings, originalSettings, jqXHR)
  settings: 現在の詳細設定設定オブジェクト
  originalSettings: 元の詳細設定設定オブジェクト
  jqXHR: jqXHR オブジェクト(jqXHR.status は HTTP のステータスコード、jqXHR.statusText にはその意味)

Ajax通信するときに必ず crossDomain を false、timeout を 100ms で行うように設定しています。

記述例
<span id="d10"></span><span id="d11"></span><br>
<span id="d20"></span><span id="d21"></span><br>

<script>
var d = {a:"AAA",b:"BBBBB",c:"C"};
$.ajaxPrefilter("text", function(settings, originalSettings, jqXHR) {
  settings.crossDomain = false;
  settings.timeout = 100;
  d10.textContent = settings.crossDomain; d11.textContent = originalSettings.crossDomain;
  d20.textContent = settings.timeout; d21.textContent = originalSettings.timeout;
});
$.ajax({
  url: "get.cgi",
  type: 'GET',
  dataType: 'text',
  data: d,
  crossDomain: true
});
</script>

originalSettings の内容は、$.ajax で指定したそのものですが、settings は Ajax通信するときに使用される全てのキーを含んだ詳細情報です。

(timeout は $.ajax で指定していないので originalSettings では空欄です。)

実行例

(3-4)ajaxTransport

send と abort という2つの関数を持ったオブジェクトを返り値として指定することで、以降の ajax()などの Ajax 処理が実行される前にそれらの関数が実行されるようにします。

send と abort は、$.ajax()によって内部的に使用されるメソッドで、それらを置き換えることになります。

$.ajax()でより高度な処理の変更を行いたい場合に、$.ajaxTransport を使用します。

メソッド引数機能戻り値
$.ajaxTransport([タイプ,] 関数)タイプ:text、html など関数を実行するデータ形式
関数:send と abort という2つのメソッドを持つオブジェクトを返す関数
function(settings, originalSettings, jqXHR)
 settings: 現在の詳細設定設定オブジェクト
 originalSettings: 元の詳細設定設定オブジェクト
 jqXHR: jqXHR オブジェクト
 戻り値: オブジェクト
  {
    send: 関数(headers, completeCallback),(注)
    abort: 関数()
  }
Ajax 通信の実際の送信を処理するオブジェクトを作成するなし
(注)
関数の形式
function(headers, completeCallback)
  headers: リクエストヘッダーのキーと値のオブジェクト
  completeCallback: Ajaxのリクエストが完了したときに呼ばれる関数

 completeCallback の形式
 function(status, statusText[, responses][, headers]) { }
   status: 受信したHTTPステータスコード(200は成功、404はページやリソースが見つからなかった など)
   statusText: 受信したステータステキスト
   responses: データタイプと値からなるオブジェクト
   headers: リクエストヘッダーのキーと値のオブジェクト

$.ajax()が内部で使用する send メソッドを独自の処理に置き換えています。

記述例
<span id="d10"></span><span id="d11"></span><br>
<span id="d20"></span><span id="d21"></span><br>
<span id="d30"></span><span id="d31"></span><br>

<script>
$.ajaxTransport("text", function(options, originalOptions, jqXHR) {
  return {
    send: function(headers, completeCallback) {
      let xhr = new XMLHttpRequest();
      xhr.addEventListener('loadend', function() { completeCallback(200, "送れたよ", {xxx: xhr.response}); });
      xhr.open("GET", options.url, false); // 同期通信
      xhr.send();
    },
    abort: function() { console.log("Aborted."); }
  };
});

$.ajax({
  url: "get.cgi",
  type: 'GET',
  dataType: 'text',
  data: "a=AAA&b=BBBBB&c=C",
  success: function(data, status, jqXHR) {d10.textContent = data; d11.textContent = jqXHR.statusText;},
  complete: function(jqXHR, status) {d20.textContent = jqXHR.responseText; d21.textContent = jqXHR.statusText;},
  statusCode:{
    200: function(data, status, jqXHR){d31.style.color = "blue"; d30.textContent = data; d31.textContent = jqXHR.statusText;},
    404: function(data, status, jqXHR){d31.style.color = "red"; d30.textContent = data; d31.textContent = jqXHR.statusText;},
  }
});
</script>
実行例

13.4  オブジェクト

jQuery で使用される主なオブジェクトについて説明します。

13.4.1  jqXHR

jqXHR は、XMLHttpRequest を拡張(オブジェクト指向的に言えば、継承して独自のメソッドやプロパティを追加)した jQuery のためのオブジェクトです。

jQuery のいろいろなメソッドの引数や戻り値として利用されています。

(1) プロパティ

jqXHR の主なプロパティです。

プロパティ
readyState通信の進歩状況を表す数値
状態説明
0UNSENTオブジェクトが生成されたが、open()は、まだ呼ばれていない。
1OPENEDサーバとの接続は確立されたが、send()は、まだ呼ばれていない。
2HEADERS_RECEIVEDsend()が呼ばれ、リクエストを送信している。headers と status が利用可能
3LOADINGレスポンスを取得中。responseText は部分的にデータを保持
4DONEレスポンスの取得完了
responseTextテキストで表されたレスポンス
statusWebサーバーから受信したステータスコード
statusText通信状況を表す文字列(OK、Not Found など)
記述例
<span id="d1"></span><br>

<!-- 以下略 -->

<script>
$("#d1").load("sample.txt", function(responseText, textStatus, jqXHR) {
  d1.textContent = jqXHR.status;
  d2.textContent = jqXHR.statusText;
  d3.textContent = jqXHR.responseText;
  d4.textContent = jqXHR.readyState;
}
</script>
sample.txt
AAA
BBBBB
C
実行例

(2) メソッド

jqXHR の主なメソッドです。

(2-1) レスポンスヘッダー

レスポンスヘッダーの変更や取得をします。

メソッド引数機能戻り値
getAllResponseHeaders()なし全てのレスポンスヘッダを取得する文字列(レスポンスがなければ null)
getResponseHeader(ヘッダ名)ヘッダ名:ヘッダの名称指定した名称のヘッダの値を取得するヘッダの値(ヘッダーが存在しない場合は null)
setRequestHeader(ヘッダ名, 値)ヘッダ名:ヘッダの名称
値:設定する値
HTTPリクエストヘッダーの値を設定する
ただし、open()の後、send()の前に呼び出す必要がある。
なし
overrideMimeType(MIMEタイプ)MIMEタイプ:設定する MIMEタイプサーバから返される MIMEタイプを上書きする
ただし、open()の後、send() の前に実行する必要がある
なし
記述例
<span id="d1"></span><br>
<span id="d2"></span><br>
<span id="d3"></span><br>

<script>
$.get("get.cgi", {
  type: 'GET',
  dataType: 'text',
  data: {color:"茜色"},
  beforeSend: function(jqXHR, settings) {
    jqXHR.setRequestHeader("param", new Date().toLocaleString());  // リクエストヘッダの設定
    jqXHR.overrideMimeType("text/plain; charset=Shift_JIS");  // 本来は UTF-8 だが Shift_JIS に変更した
  },
  success: function(data, status, jqXHR) {
    d1.textContent = jqXHR.getAllResponseHeaders();
    d2.textContent = jqXHR.getResponseHeader("Server");
    d3.textContent = data;
  }
});
</script>

本来は UTF-8 ですが Shift_JIS に変更したため、文字化けが起きています。

実行例

(2-2) 送信結果

送信結果による処理を登録します。

メソッド引数機能戻り値
always(関数)関数:実行したい関数正常時は (1)、異常時は (2)処理がどのように終了しても必ず行う処理を登録するjqXHR
done(関数)関数:実行したい関数(1)処理が正常に終了したときに行う処理を登録するjqXHR
fail(関数)関数:実行したい関数(2)処理がに異常が発生したときに行う処理を登録するjqXHR
then(関数1,関数2)関数1:処理が正常に終了したときに実行したい関数(1)
関数2:処理に異常が発生したときに実行したい関数(2)
処理が正常に終了したときと異常が発生したときに行う処理を登録するjqXHR
(1)function(データ, 状態, jqXHR)
  データ: 受信内容
  状態: 読込みの成否
状態意味
success成功
error失敗
notmodified更新されていない
timeoutタイムアウト
parsererrorパーサーエラー(構文エラー)
abortアボート
  jqXHR: jqXHR オブジェクト(jqXHR.status は HTTP のステータスコード、jqXHR.statusText にはその意味)
(2)function(jqXHR, 状態, 例外情報)
  jqXHR: jqXHR オブジェクト(jqXHR.status は HTTP のステータスコード、jqXHR.statusText にはその意味)
  状態: 読込みの成否
状態意味
error失敗
timeoutタイムアウト
parsererrorパーサーエラー(構文エラー)
abortアボート
  例外情報: HTTPステータス

記述例
<span id="d10"></span> <span id="d11"></span><br>

<!-- 以下略 -->

<script>
var m = 1;

var jqXHR = $.ajax("get.cgi", {
  type: 'GET',
  dataType: 'text',
  data: {b:"BBB"},
});
jqXHR.always(function(data, textStatus) {set("always", textStatus == "success" ? data : data.statusText);});
jqXHR.done(function(data, textStatus, jqXHR) {set("done", data);});
jqXHR.fail(function(jqXHR, textStatus, errorThrown) {set("fail", textStatus);});
jqXHR.then(function(data, textStatus, jqXHR) {set("then", data);},
           function(jqXHR, textStatus, errorThrown) {set("then", textStatus);});
jqXHR.statusCode({
  200 : function(data, textStatus, jqXHR) {set("statusCode", data);},
  404 : function(jqXHR, textStatus, errorThrown) {set("statusCode", textStatus);}
});

function set(event, data) {
  document.getElementById("d" + m + 0).textContent=event;
  document.getElementById("d" + m + 1).textContent=data;
  m++;
}
</script>

左側は正常に終了した場合で、右側はエラーが起きた(ファイルが存在しなかった)場合です。

実行例


(2-3) 送信の中断

送信を中断します。

メソッド引数機能戻り値
abort([statusText])statusText:statusText に設定する文字列規定値:abort既にリクエストが送信されていた場合、それを中断するなし
記述例
<span id="d10"></span> <span id="d11"></span><br>

<script>
var jqXHR = $.get("data/sample.txt", {
  .done(function(data, textStatus, jqXHR) {d10.textContent = "done"; d11.textContent = textStatus;})
  .fail(function(jqXHR, textStatus, errorThrown) {d10.textContent = "fail"; d11.textContent = textStatus;});
  
jqXHR.abort("わざと止めた");
</script>
実行例

13.4.2  Deferred

Deferred オブジェクトは、非同期処理に対する (複数の) コールバックのキューを管理します。

$.Deferred() メソッドの戻り値として取得できます。Deferred オブジェクトを使いこなすことで、以下のような効果が見込めます。

  • 非同期処理を連結する際、コールバック地獄から解放される(直列処理、並列処理が可能)
  • エラー処理をうまく記述できる
  • 一連の非同期処理を関数化して再利用しやすくできる

$.Deferred() では、非同期の処理それぞれに Promise オブジェクトを割り当て、そのオブジェクトの状態を伝播させていくことで処理を進めます。

非同期処理オブジェクトは、処理の状態に応じて以下の3つがあります。

pending処理が完了していない状態。progress() で実行する処理を設定できます。
resolved処理が正常に終了した状態。done() で処理の完了時に実行する処理を設定できます。resolve() などでこの状態になります。
rejected処理中に問題が発生して中断した状態。fail() メソッドで中断時に実行する処理を設定できます。reject() などでこの状態になります。

状態の変化は、「pending→resolved(正常終了)」か「pending→rejected(異常終了)」の2つだけです。一度変化したら元には戻りません。

(1) メソッド

Deferred オブジェクトの主なメソッドです。

(1-1) Promise オブジェクトの生成

Promise オブジェクトを生成します。

Promise オブジェクトは $.Deferred() が生成するオブジェクトで、Deferred オブジェクトは Promise オブジェクトを内包しています。Deferred オブジェクトとPromise オブジェクトは常に1対1で作成され、対応する Deferred オブジェクトだけが Promise オブジェクトの内部状態を変更できます。

メソッド引数機能戻り値
promise([対象])対象:Object オブジェクトDeferred オブジェクトから Promise オブジェクトを作成する
対象が指定されている場合はそのオブジェクトを Promise オブジェクトとする
Promise オブジェクト
記述例
<span id="d10"></span><br>
<span id="d20"></span> <span id="d21"></span><br>

<script>
var df = $.Deferred();
var pr = df.promise();
d10.textContent = pr.state();  // Deferred オブジェクトから Promise オブジェクトを生成する
pr = df.promise({a:"AAA"});    // 引数のオブジェクトを Promise オブジェクトとする
d20.textContent = pr.state();
d21.textContent = pr.a;
</script>
実行例

「13.3.11 非同期処理」 「(1-1)非同期処理オブジェクトの生成」 Deferred オブジェクト.promise も参照してください。


(1-2) 非同期処理の設定

正常終了時(resolved)、異常終了時(rejected)あるいは、処理が完了していないとき(pending)に実行する処理を設定します。

メソッド引数機能戻り値
always([関数[, ...]])関数:実行したい処理resolved、rejected のいずれの場合でも、実行したいコールバック関数を指定するDeferred オブジェクト
done(関数[, ...])関数:実行したい処理resolved の場合に、実行したいコールバック関数を指定するDeferred オブジェクト
fail(関数[, ...])関数:実行したい処理rejected の場合に、実行したいコールバック関数を指定するDeferred オブジェクト
progress(関数[, ...])関数:実行したい処理pending の場合に、実行したいコールバック関数を指定するDeferred オブジェクト
then(done関数[,fail関数[,progress関数]])関数:実行したい処理resolve、reject、pending のそれぞれの場合に、実行したいコールバック関数を指定する新たなDeferred オブジェクト(注)
(注)then メソッドは resolved である Deferred オブジェクトを生成しそれを返します。それ以外のメソッドは自身のオブジェクトを返します
記述例
<span id="d1"></span><br>

<!-- 以下略 -->


<script>
var m = 1;

var df = $.Deferred();
df.progress(function() {set("progress");});
df.then(function() {set("then1");},
        function() {set("then2");},
        function() {set("then3");});
df.done(function() {set("done");});
df.fail(function() {set("fail");});
df.always(function() {set("always");});

df.notify();df.notify();
df.resolve();  // 正常終了時は resolve、異常終了時は reject を実行する

function set(event) {
  document.getElementById("d" + m++).textContent=event;
}
</script>

左側は正常に終了(resolve)した場合で、右側は異常終了(reject)した場合です。

実行例

then などの各メソッドは Deferred オブジェクトを返すので、次のようにメソッドを連結して記述することもできます。

ただし、then メソッドは resolved である Deferred オブジェクトを生成して返すので、左の例のように、rejected であったとしても then メソッド以降は resolved の処理になってしまいます(then2 の次に fail ではなく done が表示されています)。

これを避けるには、then メソッドの fail関数で明示的に reject() を実行した Deferred オブジェクトを返します。

記述例
var df = $.Deferred();
df.then(function() {set("then1");},
        function() {set("then2");},  // resolved になる
        function() {set("then3");})
  .done(function() {set("done");})
  .fail(function() {set("fail");});

df.notify();df.notify();
df.reject();  // 異常終了

var df = $.Deferred();
df.then(function() {set("then1");},
        function() {set("then2");
                    return df.reject();}) // rejectedを返す
        function() {set("then3");},
  .done(function() {set("done");})
  .fail(function() {set("fail");});

df.notify();df.notify();
df.reject();  // 異常終了
実行例

「13.3.11 非同期処理」 (1-2)非同期処理の設定 も参照してください。


(1-3) 非同期処理の実行

正常終了時(resolve)、異常終了時(reject)あるいは、処理が完了していないとき(pending)に、それぞれ設定されている関数を呼び出すために実行します。

メソッド引数機能戻り値
resolve([引数[, ...]])引数:done関数やthen関数に渡す引数done で指定した関数を実行する(正常終了)Deferred オブジェクト
resolveWith(thisObject[, 引数])thisObject:done関数で this として扱われる値
引数:done関数やthen関数に渡す引数の配列(注)
done で指定した関数を実行する(正常終了)Deferred オブジェクト
reject([引数[, ...]])引数:fail関数やthen関数に渡す引数fail で指定した関数を実行する(異常終了)Deferred オブジェクト
rejectWith(thisObject[, 引数])thisObject:fail関数で this として扱われる値
引数:fail関数やthen関数に渡す引数の配列(注)
fail で指定した関数を実行する(異常終了)Deferred オブジェクト
notify([引数[, ...]])引数:progress関数やthen関数に渡す引数progress で指定した関数を実行する(実行中)Deferred オブジェクト
notifyWith(thisObject[, 引数])thisObject:progress関数で this として扱われる値
引数:progress関数やthen関数に渡す引数の配列(注)
progress で指定した関数を実行する(実行中)Deferred オブジェクト
注)引数は、ひとつだけでも配列として指定する

done や fail などに設定された関数内で this を使用した場合、resolve や reject など With が付かない関数を実行したときは Window オブジェクトが this の値になります。それに対して、resolveWith や rejectWith など With が付く関数を実行したときは、その第1引数が関数内の this の値になります。

下の例で、notify を実行した場合は、progress 内の this.mark は Window オブジェクトの mark すなわち "." となりますが、notifyWith を実行した場合は、progress 内の this.mark は notifyWith の第1引数である Emphasis オブジェクトの mark すなわち "+" となります。

なお、this については 「7.5 this」 を参考にしてください。

記述例
<span id="d1"></span><br>

<!-- 以下略 -->


<script>
var mark = ".";
var lp = "(";
var rp = ")";
var symbol = new Emphasis(); 

def().resolve(d1, "成功", new Date());
def().resolveWith(symbol, [d2, "成功", new Date()]);
def().reject(d3, "失敗", "原因不明");
def().rejectWith(symbol, [d4, "失敗", "原因不明"]);
def().notify(d5);
def().notifyWith(symbol, [d6]);


function def() {
  let df = $.Deferred();
  df.done(function(e, r, tm) { e.textContent += r + this.lp + tm.toLocaleString() + this.rp; });
  df.fail(function(e, r, rs) { e.textContent += r + this.lp + rs + this.rp; });
  df.progress(function(p) { p.textContent += this.mark; });
  return df;
}

function Emphasis() {
  this.mark = "+";
  this.lp = "《";
  this.rp = "》";
}
</script>
実行例

「13.3.11 非同期処理」 (1-3)非同期処理の実行 も参照してください。


(1-4) 非同期処理の状態

正常終了(resolve)、異常終了(reject)あるいは、処理が完了していない(pending)のどの状態にあるのかを調べます。

メソッド引数機能戻り値
state()なしDeferredオブジェクトの現在の状態を調べる"pending"  処理が完了していない
"resolved" 正常終了している
"rejected" 異常終了している
記述例
<span id="d10"></span> <span id="d11"></span><br>

<!-- 以下略 -->


<script>
var m = 1;

var df = $.Deferred();
df.progress(function() {set("progress", df);});
df.done(function() {set("done", df);});
df.fail(function() {set("fail", df);});
df.always(function() {set("always", df);});

df.notify();df.notify();
df.resolve();  // 正常終了時は resolve、異常終了時は reject を実行する

function set(event, df) {
  document.getElementById("d" + m + 0).textContent=event;
  document.getElementById("d" + m + 1).textContent=df.state();
  m++;
}
</script>

左側は正常に終了(resolve)した場合で、右側は異常終了(reject)した場合です。

実行例

13.4.3  Promise

Promise オブジェクトは、Deferred オブジェクトから生成される Deferred オブジェクトのサブセットです。非同期処理の最終的な正常終了もしくは異常終了を表します。

非同期処理オブジェクトは、処理の状態に応じて以下の3つがあります。

pending処理が完了していない状態。progress() で実行する処理を設定できます。
resolved処理が正常に終了した状態。done() で処理の完了時に実行する処理を設定できます。resolve() などでこの状態になります。
rejected処理中に問題が発生して中断した状態。fail() メソッドで中断時に実行する処理を設定できます。reject() などでこの状態になります。

状態の変化は、「pending→resolved(正常終了)」か「pending→rejected(異常終了)」の2つだけです。一度変化したら元には戻りません。

(1) メソッド

Promise オブジェクトの主なメソッドです。

(1-1) 非同期処理の設定

正常終了時(resolve)、異常終了時(reject)あるいは、処理が完了していないとき(pending)に実行する処理を設定します。

メソッド引数機能戻り値
always([関数[, ...]])関数:実行したい処理resolve、reject のいずれの場合でも、実行したいコールバック関数を指定するPromise オブジェクト
catch([関数[, ...]])関数:実行したい関数処理がに異常が発生(reject)したときに行う処理を登録する新たな Promise オブジェクト(注)
done([関数[, ...]])関数:実行したい関数処理が正常に終了(resolve)したときに行う処理を登録するPromise オブジェクト
fail([関数[, ...]])関数:実行したい関数処理がに異常が発生(reject)したときに行う処理を登録するPromise オブジェクト
progress(関数[, ...])関数:実行したい処理pending の場合に、実行したいコールバック関数を指定するPromise オブジェクト
then(done関数[,fail関数[,progress関数]])関数:実行したい処理resolve、reject、pending のそれぞれの場合に、実行したいコールバック関数を指定する
複数記述して処理の連結ができる
新たな Promise オブジェクト(注)
(注)then や catch メソッドは resolved である Deferred オブジェクトを生成しそれを返します。それ以外のメソッドは自身のオブジェクトを返します
記述例
<span id="d1"></span><br>

<!-- 以下略 -->


<script>
function exec() {
  let df = $.Deferred();
  df.notify(" notify");
  df.resolve(" resolve");  // 正常終了時は resolve("resolve")、異常終了時は reject("reject") を実行する
  return df.promise();
}

var pr = exec();
pr.then(function(result){return result + " then11";},
        function(result){return new $.Deferred().reject(result + " then12").promise();},
        function(result){return result + " then13";})
  .then(function(result){return result + " then21";},
        function(result){return new $.Deferred().reject(result + " then22").promise();},
        function(result){return result + " then23";})
  .progress(function(result){d1.textContent += result + " progress";})      // notify で実行される
  .always(function(result){d2.textContent += result + " always";})          // resolve でも reject でも実行される
  .done(function(result){d3.textContent += result + " done";})              // resolve で実行される
  .fail(function(result){d4.textContent += result + " fail";});             // reject で実行される
  .catch(function(result){d5.textContent += result + " catch";});           // reject で実行される
</script>

左側は正常に終了(resolve)した場合で、右側は異常終了(reject)した場合です。

実行例

.then に記述された関数は順次実行されます。

この例では、処理に失敗(reject)しています(①)ので .then の2つ目の引数の位置に書かれた関数(fail 関数)が実行されます。

ただし、最初の .then(②)には fail 関数がないので、何も実行されません。

次の .then(③)には fail 関数があるので実行されますが、エラー回復処理に失敗した(rejected である promise オブジェクトを返している)ので、引き続き rejected です。

その次の .then(④)では、エラー回復処理に成功したので、明示的に promise オブジェクトを返さず return しています(resolved である promise オブジェクトが返る)。

そして、resolved なので、.done(⑤)が実行されます。

記述例
<span id="d1"></span><br>

<script>
var df = $.Deferred();
var pr = df.promise();

pr.then(function(result){return result + " then01";})  // ② fail関数がないので、rejected のまま
  .then(function(result){return result + " then11";},
        function(result){return recovery1(result);})   // ③ エラー回復失敗。新たに rejected である promise オブジェクトを生成する
  .then(function(result){return result + " then21";},
        function(result){return recovery2(result)},    // ④ エラー回復成功。resolved である promise オブジェクトが生成される
  .done(function(result){d1.textContent += result + " done";})     // ⑤ resolved のとき実行される
  .fail(function(result){d1.textContent += result + " fail";});       // rejected のとき実行される

df.reject(" reject");  // ① 処理に失敗した(rejected になる)

function recovery1(arg) {
  // エラー回復処理
  return new $.Deferred().reject(arg + " then12(エラー継続)").promise();  // 失敗した。新たに rejected にする
}
function recovery2(arg) {
  // 別のエラー回復処理
  return arg + " then22(エラー回復)";  // 成功した。resolved になる
}

</script>
実行例

(1-2) 非同期処理の状態

正常終了(resolve)、異常終了(reject)あるいは、処理が完了していない(pending)のどの状態にあるのかを調べます。

メソッド引数機能戻り値
state()なしPromiseオブジェクトの現在の状態を調べる"pending"  処理が完了していない
"resolved" 正常終了している
"rejected" 異常終了している
記述例
<span id="d10"></span> <span id="d11"></span><br>

<!-- 以下略 -->


<script>
var m = 1;

var df = $.Deferred();
var pr = df.promise();
df.progress(function() {set("progress", pr);});
df.done(function() {set("done", pr);});
df.fail(function() {set("fail", pr);});
df.always(function() {set("always", pr);});

df.notify();df.notify();
df.resolve();  // 正常終了時は resolve、異常終了時は reject を実行する

function set(event, pr) {
  document.getElementById("d" + m + 0).textContent=event;
  document.getElementById("d" + m + 1).textContent=pr.state();
  m++;
}
</script>

左側は正常に終了(resolve)した場合で、右側は異常終了(reject)した場合です。

実行例