doc drawn up: 2003-12-10 .. 2011-06-06

JavaScript 研究


JavaScript リファレンス | JavaScript ガイド | DOM リファレンス | Form (HTML5)


AJaXAsynchronous JavaScript + XML
AT 仕様のインターネット・ブラウジング

流行語の発生源はこちら(?)。ここの図解を見るとわかるが、イメージ的には「(従来的な意味での)ブラウザとサーバとの間に Ajax エンジンが追加される」というよりも、「ユーザと(従来的な意味での)ブラウザとの間に、さらに Ajax の援用による UI 層が増えた」という感じの方が、より的確な感じがする。要するに、自動車の運転で言うと、MT(マニュアル)車か AT(オートマチック)車かという違いに相当するといえる。非 Ajax(従来のブラウジング)の場合では、ユーザが直接ブラウザを操作して、HTTP 要求を発信し、サーバからの応答を受け取っていたわけで、MT 車でクラッチの On/Off を運転者が直接切り替えながら変速ギアをシフト操作するのに相当する。一方、Ajax の場合、HTTP 通信の要求&応答ということによる動作制限をユーザが直接意識する必要がなくなり、AT 車でギアシフトを意識せずにハンドル操作とアクセル&ブレーキ操作だけに集中していればいいケースに相当する。

MT 車の場合、クラッチを切っている時にアクセルを踏んで加速することはできない(エンジンが空吹きするだけ)。つまり、運転者は、クラッチの On/Off に直接アクセル操作の影響を受ける。一方、AT 車の場合クラッチは実質上存在しないので、運転者は好きなときにアクセルを踏んで加速操作することができる。同様に、非 Ajax では、HTTP 要求をサーバに送信してサーバからの応答を待っている間、ユーザは新しい操作ができない。それに対して Ajax では、HTTP 要求をサーバに送信して応答待ちの場合でも、ユーザは気にせずに新しい HTTP 要求を発行するような種類の操作を行うことができる。このあたり、例えば高橋登史朗「Ajax Sync(同期)とAsync(非同期)」に掲載の 1 番目のサンプルなど体感的にわかりやすい。

まあ、実際のところは、Ajax エンジンとなる「XMLHttpRequest オブジェクト」が、背後でブラウザの再読込みボタンをこまめに押しているような感じで、いわゆるポーリングを行い、サーバからのHTTP 応答に対して、必要があれば JavaScript で定義された動作を行って、ブラウザに表示するページの必要な部分に反映するという形になっているようである。つまり、ユーザから見えない背後の部分では、相変わらず従来と同じく、同期的な HTTP 通信作業が行われているし、HTTP 通信そのものが何か全く従来と違った新しいものに取り替えられたわけでは、決してない。

それでも、例えば Web チャットシステムのようなものを考えてみると、非 Ajax の場合は、ページを定期的にリロードさせるような形で実現するのが普通であった。つまり、ブラウザの右上なんかにあるアイコンが定期的にぐりぐりと読み込み中となってページ全体がリフレッシュされる。新しい書込があるとそのコメントが追加されているし、新しい書込がなかった場合でも、ブラウザは定義された通りに定期的にページをリロード動作することになる。一方、Ajax の Web チャットシステムであれば、Ajax エンジン(XMLHttpRequest オブジェクト)が定期的にポーリングを行い、サーバ上のデータに新しいコメントが書き込まれていない場合は、無視してブラウザに表示したページに変化を与えない。Ajax エンジンが新しいコメントの書込を検知したときのみ、ページ全体をリフレッシュするなり、ページの必要な部分のみに更新を反映するなり、動作させればいいのである。ともかく、新しい書込がないのに定期的に虚しくページリロードを行う動作を抑制させられるだけでも、ユーザ感覚的には、随分とスマートな感じがすることは間違いない。車で言うと、「アイドリング・ストップ!」という感じだろうか?(笑) 非 Ajax では、Web チャットというものは、チャット専用のプロトコルによる IRC (Internet Relay Chat) のクライアントに比べて随分見劣りしたが、Ajax では、IRC に比べてそれほどユーザ感覚的に遜色のないチャットクライアントも実現できそうだ。


サンプル集

表示するアイコン画像とプルダウンオプションの連動

ゲームに応用が効く技。注意点としては、XHTML では、form および img 要素について、「個々の要素を識別するため」には name 属性ではなく id 属性を使わなければならない点(IE 6 と Firefox 2 では既に対応済)である。(※ただし、form でサーバに送信するデータ(name=value の形式)の属性を識別するための name 属性の使用については従来のままなので混同しないこと)

アイコン画像

<script type="text/javascript">
function changeImg() {
    num = document.forms["sample-01"].pulldownMenu.selectedIndex;
    document.images["icons"].src = "./icons/" + num + ".png";
}
</script>
<form id="sample-01" action="">
<img src="./icons/0.png" id="icons" alt="アイコン画像" width="64" height="64" /><br />
<select id="pulldownMenu" onchange="changeImg()">
<option value="0"> 陰陽 </option>
<option value="1">スマイル</option>
<option value="2">ロータス</option>
</select>
</form>

画像タイルのクリックとフォーム入力の連動

ゲームで地図上の座標をフォームで指定入力しなければならないような場合、地図上の画像タイルを直接クリックして指定できれば、ユーザインタフェース的な快適性に抜群に貢献する。

href="javascript: void(0)" という記述は、JavaScript の動作のためにクリック可能なリンクを用いつつも、実際にはどこかリンク先の別の URI へジャンプするわけでもないというような場合に、フェイク的手段としてよく用いられる手である。

もちろん、このテクニックは、画像タイルに対するリンクでなくとも、単なる文字リンクを用いる場合にも応用が利く技である。

(※ onclick 属性だけでも動作するが、W3C の「アクセス指針技術文書」に従い、onkeypress 属性も併記している)

X=0X=1
Y=0座標(0,0)座標(1,0)
Y=1座標(0,1)座標(1,1)

座標(x, y) = ( , )

<script type="text/javascript">
function loc(x, y) {
    document.forms["sample-02"].x_axis.options[x].selected = true;
    document.forms["sample-02"].y_axis.options[y].selected = true;
}
</script>
<table>
<tr style="text-align: center"><td></td><td>X=0</td><td>X=1</td></tr>
<tr><td>Y=0</td><td><a href="javascript: void(0)" onclick="loc(0,0)" onkeypress="loc(0,0)"><img src="./icons/0.png" title="座標(0,0)" alt="座標(0,0)" width="64" height="64" /></a></td><td><a href="javascript: void(0)" onclick="loc(1,0)" onkeypress="loc(1,0)"><img src="./icons/1.png" title="座標(1,0)" alt="座標(1,0)" width="64" height="64" /></a></td></tr>
<tr><td>Y=1</td><td><a href="javascript: void(0)" onclick="loc(0,1)" onkeypress="loc(0,1)"><img src="./icons/2.png" title="座標(0,1)" alt="座標(0,1)" width="64" height="64" /></a></td><td><a href="javascript: void(0)" onclick="loc(1,1)" onkeypress="loc(1,1)"><img src="./icons/3.png" title="座標(1,1)" alt="座標(1,1)" width="64" height="64" /></a></td></tr>
</table>
<form id="sample-02" action="">
<p>座標(x, y) = (
<select id="x_axis">
<option value="0">0</option>
<option value="1">1</option>
</select>,
<select id="y_axis">
<option value="0">0</option>
<option value="1">1</option>
</select>
)</p>
</form>

ラジオボタンの選択クリックによる Submit ボタンへのジャンプ

location.replace(URI) という JavaScript メソッドを使って、URI にページ内のアンカーポイントを指定することによって、フォームの Submit ボタンへ一気にジャンプする。一番上の「Go to Submit」ボタンがそれだが、この技は、例えばその次にある「東京」から「仙台」に至る多数に連なったラジオボタンから一つだけ選択して Submit ボタンを押すような、縦長のフォームページにおいて、ユーザがページをスクロールダウンする手間を省くというようなユーザインタフェースの快適性の実現に応用できる。

(※ onclick 属性だけでも動作するが、W3C の「アクセス指針技術文書」に従い、onkeypress 属性も併記している)

北海道
青森県
岩手県
宮城県
秋田県
山形県
福島県
茨城県
栃木県
群馬県
埼玉県
千葉県
東京都
神奈川県
新潟県
富山県
石川県
福井県
山梨県
長野県
岐阜県
静岡県
愛知県
三重県
滋賀県
京都府
大阪府
兵庫県
奈良県
和歌山県
鳥取県
島根県
岡山県
広島県
山口県
徳島県
香川県
愛媛県
高知県
福岡県
佐賀県
長崎県
熊本県
大分県
宮崎県
鹿児島県
沖縄県

<script type="text/javascript">
function goto_sbm() {
    location.replace("#submit");
}
</script>
<form action="" style="border: 1px solid black; width: 150px; text-align: center">
<p><input type="button" value="Go to Submit" onclick="goto_sbm()" onkeypress="goto_sbm()" /></p>
<p style="text-align: left; margin-left: 2em">
<input type="radio" name="pref" value="JP-01" onclick="goto_sbm()" onkeypress="goto_sbm()" />北海道<br />
<input type="radio" name="pref" value="JP-02" onclick="goto_sbm()" onkeypress="goto_sbm()" />青森県<br />
<input type="radio" name="pref" value="JP-03" onclick="goto_sbm()" onkeypress="goto_sbm()" />岩手県<br />
<input type="radio" name="pref" value="JP-04" onclick="goto_sbm()" onkeypress="goto_sbm()" />宮城県<br />
<input type="radio" name="pref" value="JP-05" onclick="goto_sbm()" onkeypress="goto_sbm()" />秋田県<br />
<input type="radio" name="pref" value="JP-06" onclick="goto_sbm()" onkeypress="goto_sbm()" />山形県<br />
<input type="radio" name="pref" value="JP-07" onclick="goto_sbm()" onkeypress="goto_sbm()" />福島県<br />
<input type="radio" name="pref" value="JP-08" onclick="goto_sbm()" onkeypress="goto_sbm()" />茨城県<br />
<input type="radio" name="pref" value="JP-09" onclick="goto_sbm()" onkeypress="goto_sbm()" />栃木県<br />
<input type="radio" name="pref" value="JP-10" onclick="goto_sbm()" onkeypress="goto_sbm()" />群馬県<br />
<input type="radio" name="pref" value="JP-11" onclick="goto_sbm()" onkeypress="goto_sbm()" />埼玉県<br />
<input type="radio" name="pref" value="JP-12" onclick="goto_sbm()" onkeypress="goto_sbm()" />千葉県<br />
<input type="radio" name="pref" value="JP-13" onclick="goto_sbm()" onkeypress="goto_sbm()" />東京都<br />
<input type="radio" name="pref" value="JP-14" onclick="goto_sbm()" onkeypress="goto_sbm()" />神奈川県<br />
<input type="radio" name="pref" value="JP-15" onclick="goto_sbm()" onkeypress="goto_sbm()" />新潟県<br />
<input type="radio" name="pref" value="JP-16" onclick="goto_sbm()" onkeypress="goto_sbm()" />富山県<br />
<input type="radio" name="pref" value="JP-17" onclick="goto_sbm()" onkeypress="goto_sbm()" />石川県<br />
<input type="radio" name="pref" value="JP-18" onclick="goto_sbm()" onkeypress="goto_sbm()" />福井県<br />
<input type="radio" name="pref" value="JP-19" onclick="goto_sbm()" onkeypress="goto_sbm()" />山梨県<br />
<input type="radio" name="pref" value="JP-20" onclick="goto_sbm()" onkeypress="goto_sbm()" />長野県<br />
<input type="radio" name="pref" value="JP-21" onclick="goto_sbm()" onkeypress="goto_sbm()" />岐阜県<br />
<input type="radio" name="pref" value="JP-22" onclick="goto_sbm()" onkeypress="goto_sbm()" />静岡県<br />
<input type="radio" name="pref" value="JP-23" onclick="goto_sbm()" onkeypress="goto_sbm()" />愛知県<br />
<input type="radio" name="pref" value="JP-24" onclick="goto_sbm()" onkeypress="goto_sbm()" />三重県<br />
<input type="radio" name="pref" value="JP-25" onclick="goto_sbm()" onkeypress="goto_sbm()" />滋賀県<br />
<input type="radio" name="pref" value="JP-26" onclick="goto_sbm()" onkeypress="goto_sbm()" />京都府<br />
<input type="radio" name="pref" value="JP-27" onclick="goto_sbm()" onkeypress="goto_sbm()" />大阪府<br />
<input type="radio" name="pref" value="JP-28" onclick="goto_sbm()" onkeypress="goto_sbm()" />兵庫県<br />
<input type="radio" name="pref" value="JP-29" onclick="goto_sbm()" onkeypress="goto_sbm()" />奈良県<br />
<input type="radio" name="pref" value="JP-30" onclick="goto_sbm()" onkeypress="goto_sbm()" />和歌山県<br />
<input type="radio" name="pref" value="JP-31" onclick="goto_sbm()" onkeypress="goto_sbm()" />鳥取県<br />
<input type="radio" name="pref" value="JP-32" onclick="goto_sbm()" onkeypress="goto_sbm()" />島根県<br />
<input type="radio" name="pref" value="JP-33" onclick="goto_sbm()" onkeypress="goto_sbm()" />岡山県<br />
<input type="radio" name="pref" value="JP-34" onclick="goto_sbm()" onkeypress="goto_sbm()" />広島県<br />
<input type="radio" name="pref" value="JP-35" onclick="goto_sbm()" onkeypress="goto_sbm()" />山口県<br />
<input type="radio" name="pref" value="JP-36" onclick="goto_sbm()" onkeypress="goto_sbm()" />徳島県<br />
<input type="radio" name="pref" value="JP-37" onclick="goto_sbm()" onkeypress="goto_sbm()" />香川県<br />
<input type="radio" name="pref" value="JP-38" onclick="goto_sbm()" onkeypress="goto_sbm()" />愛媛県<br />
<input type="radio" name="pref" value="JP-39" onclick="goto_sbm()" onkeypress="goto_sbm()" />高知県<br />
<input type="radio" name="pref" value="JP-40" onclick="goto_sbm()" onkeypress="goto_sbm()" />福岡県<br />
<input type="radio" name="pref" value="JP-41" onclick="goto_sbm()" onkeypress="goto_sbm()" />佐賀県<br />
<input type="radio" name="pref" value="JP-42" onclick="goto_sbm()" onkeypress="goto_sbm()" />長崎県<br />
<input type="radio" name="pref" value="JP-43" onclick="goto_sbm()" onkeypress="goto_sbm()" />熊本県<br />
<input type="radio" name="pref" value="JP-44" onclick="goto_sbm()" onkeypress="goto_sbm()" />大分県<br />
<input type="radio" name="pref" value="JP-45" onclick="goto_sbm()" onkeypress="goto_sbm()" />宮崎県<br />
<input type="radio" name="pref" value="JP-46" onclick="goto_sbm()" onkeypress="goto_sbm()" />鹿児島県<br />
<input type="radio" name="pref" value="JP-47" onclick="goto_sbm()" onkeypress="goto_sbm()" />沖縄県<br />
</p>
<p id="submit"><input type="submit" value="Submit" /></p>
</form>

<coding>