DOM イベント処理 (2) mousemove ~ Ajax による改良
はじめに
この資料では前回の資料 "DOM イベント処理 (2)" で作ったコードを改良します。前回の記事を FTP にアップロードして自宅以外の(特に回線の細い)環境から見てみると、画像のロード時間が無視できないことに気づきました。このため、この画像のロードを 非同期で行い、画像のロード中は "Loading..." のメッセージを表示し、ロードが終了したらメッセージを消します。
出来上がりは次のようになります。
Loading...
さっそく解説に入ります。
1. 考え方
いまどきのメジャーなブラウザはそのままでも、もちろん非同期で画像をダウンロードするには違いがないのですが、前回のコードでは小さ な領域にロー ドするわりに画像が巨大(詳細図のため)なため、待たされることに違和感を感じてしまいました。このため、今何をやっているのか、ユーザーに状況をレポー トすることを考えました。すなわち、画像を読み込んでいる最中は "Loading..." というメッセージを表示しておき、画像のロードが終わったらそのメッセージを消します。ちなみに、ここでは画像のロード場所はブラウザのキャッシュに頼っ ています(今のところこれでうまくいくので深入りしないことにします。あしからず)。
さて、非同期読み込みには Ajax の典型的な手法を使っています。例によって、window の load イベントハンドラでスクリプトを初期化していますが、初期化時にいきなり HTTP リクエストを送信します。
function initScript(e) {
SendRequest( g_sImageURL );
}
addEvent(window, 'load', initScript, false);
ここで g_sImageURL は画像のURLです。 addEvent については以前の資料をご覧ください。
SendRequest は次のコードです。
function SendRequest (url, params, method)
{
if (!method) {
method =
"GET";
}
g_Request = GetXmlHttpRequest();
if ( !g_Request ) {
return;
}
g_Request.onreadystatechange =
OnReadyState;
g_Request.open(method, url, true);
g_Request.send(params);
}
g_Request には XmlHttpRequest オブジェクトを保持します。オブジェクトの readyState の変更イベントハンドラとして OnReadyState を指定します。ステートの変更は一般に、LOADING(1)、LOADED(2), INTERACTIVE(3), COMPLETE(4) の順番で変わります。OnReadyStateでステートをチェックして、それが COMPLETE(4) ならばロードが完了したとしています。ちゃんとチェックするならば HTTP ステータスまで見るべきですが、今回は実装していません(手抜きです)。
オブジェクトの取得は次のコードです。
function GetXmlHttpRequest () {
var req = null;
if ( window.XMLHttpRequest ) {
req = new
XMLHttpRequest();
}
else if ( window.ActiveXObject ) {
req = new
ActiveXObject("Msxml2.XMLHTTP");
}
return req;
}
window.ActiveXObject = true のコードパスは MS-IE 用ですが、こちらは Msxml2.XMLHTTP 一種類にしています。
OnReadyState にて、画像ロードが完了したことを確認したら、"Loading..." というメッセージを示していたテキストノードを削除して完了です。
function OnReadyState(e) {
if ( g_Request.readyState ==
READY_STATE_COMPLETE ) {
var elm =
document.getElementById('msg');
//
elm.innerHTML = '';
elm.parentNode.removeChild(elm);
startPlaying();
}
else {
// do
nothing
}
}
2. リスト
リスト全体は以下のようになります。前回、前々回の延長でもありますので、適宜補ってください。
//
// 1/10/2006
Keisuke Oyama
//
var g_Request
= null;
var READY_STATE_UNINITIALIZED = 0;
var
READY_STATE_LOADING
= 1;
var
READY_STATE_LOADED
= 2;
var READY_STATE_INTERACTIVE = 3;
var
READY_STATE_COMPLETE
= 4;
var g_sImageURL = './scr09/pic3.jpg';
var isIE = false;
///////////////////////////////////////////////////////////////////////////////
function startPlaying(e)
{
if ( document.getElementById ) {
var
thumbnail = document.getElementById('thumb');
addEvent(thumbnail, 'mousemove', onMouseMove, false);
var
elmVwr = document.getElementById('viewer');
elmVwr.style.background = 'url(' + g_sImageURL + ')';
elmVwr.style.backgroundRepeat = 'no-repeat';
}
if ( !window.opera &&
navigator.userAgent.indexOf('MSIE') != -1 ) {
isIE =
true;
}
}
... 途中省略 ...
///////////////////////////////////////////////////////////////////////////////
function SendRequest
(url, params, method) {
if (!method) {
method =
"GET";
}
g_Request = GetXmlHttpRequest();
if ( !g_Request ) {
return;
}
g_Request.onreadystatechange =
OnReadyState;
g_Request.open(method, url, true);
g_Request.send(params);
}
///////////////////////////////////////////////////////////////////////////////
function GetXmlHttpRequest
() {
var req = null;
if ( window.XMLHttpRequest ) {
req = new
XMLHttpRequest();
}
else if ( window.ActiveXObject ) {
req = new
ActiveXObject("Msxml2.XMLHTTP");
}
return req;
}
///////////////////////////////////////////////////////////////////////////////
function OnReadyState(e)
{
if ( g_Request.readyState ==
READY_STATE_COMPLETE ) {
var elm =
document.getElementById('msg');
elm.parentNode.removeChild(elm);
startPlaying();
}
else {
// do
nothing
}
}
///////////////////////////////////////////////////////////////////////////////
function initScript(e)
{
SendRequest( g_sImageURL );
}
///////////////////////////////////////////////////////////////////////////////
addEvent(window,
'load', initScript, false);