riina-k.net

音楽・小説・プログラミングを手がけるリイナの拠点。

遅延ロードをライブラリ化してみた

先ほどのエントリー「画像ロード時のエラー制御で試行錯誤」で組んだjavascript、エラー制御というより「読み込み中」的な意味で使い回しができそうなので汎用性を持たせてライブラリ化。

delayload.js

DelayLoad = {
	class: "delay",
	error: "error",
	retry: 1,
	init: function(params)
	{
		if ( params && params.hasOwnProperty("class") ) {
			this.class = params.class;
		}
		if ( params && params.hasOwnProperty("retry") ) {
			this.retry = params.retry;
		}
		if ( params && params.hasOwnProperty("error") ) {
			this.error = params.error;
		}
		
		// 対象のjQueryオブジェクトにパラメータを設定
		var jqTarget = jQuery( "*[class^='" + this.class + "']" );
		for ( i=0; i<jqTarget.length; ++i ) {
			jQuery.data( jqTarget.get(i), "retry", this.retry );
			jQuery.data( jqTarget.get(i), "error", this.error );
		}
		jqTarget.each(function(){
			// 引数をパース
			var paramsString = this.className.split(";")[1];
			var arrParams = paramsString.match(/^params=\{(.*?)\}$/)[1].match(/([a-z]+):('(.*?)'|[0-9]+)/g);
			var objParams = {};
			for ( i=0; i<arrParams.length; ++i ) {
				var tmp = arrParams[i].split(":");
				if ( tmp[1].match(/^'(.*?)'$/) ) {
					objParams[ tmp[0] ] = RegExp.$1;
				} else {
					objParams[ tmp[0] ] = tmp[1];
				}
			}
			if ( !objParams.hasOwnProperty("url") ) {
				throw "DelayLoad: url required";
			}
			if ( !objParams.hasOwnProperty("title") ) {
				objParams.title = "";
			}
			if ( !objParams.hasOwnProperty("retry") ) {
				objParams.retry = jQuery.data( this, "retry" );
			}
			objParams.error = jQuery.data( this, "error" );
			
			var jqImg = jQuery("<img />");
			// エラー時のイベントハンドラ
			jqImg.bind("error", function(e){
				// 再試行回数だけリロード
				var retry = jQuery.data( this, "retry" );
				if ( --retry > 0 ) {
					jQuery.data( this, "retry", retry );
					this.src = this.src;
				} else {
					// 試行回数切れ
					var target = jQuery.data( this, "target" );
					var error = jQuery.data( this, "error" );
					target.replaceWith(error);
					// 後始末
					jQuery.removeData( this, "retry" );
					jQuery.removeData( this, "error" );
					jQuery.removeData( this, "target" );
				}
			});
			// ロード時のイベントハンドラ
			jqImg.bind("load", function(e){
				var target = jQuery.data( this, "target" );
				target.replaceWith( jQuery(this) );
				// 後始末
				jQuery.removeData( this, "retry" );
				jQuery.removeData( this, "error" );
				jQuery.removeData( this, "target" );
			});
			// 再試行回数を設定
			jQuery.data( jqImg.get(0), "retry", objParams.retry );
			// エラーHTMLを設定
			jQuery.data( jqImg.get(0), "error", objParams.error );
			// 画像置換対象
			jQuery.data( jqImg.get(0), "target", jQuery(this) );
			// 読み込み
			if ( objParams.hasOwnProperty("width") ) {
				jqImg.attr("width", objParams.width);
			}
			if ( objParams.hasOwnProperty("height") ) {
				jqImg.attr("height", objParams.height);
			}
			if ( objParams.hasOwnProperty("title") ) {
				jqImg.attr("alt", objParams.title);
			}
			jqImg.attr("src", objParams.url);
		});
	}
};

使い方はこんな感じ。

<script type="text/javascript" src="js/jquery.js"></script>
<script type="text/javascript" src="js/delayload.js"></script>
<script type="text/javascript">
	jQuery(function(){
		DelayLoad.init({
			error: "<strong style='color:red;'>読み込みに失敗しました</strong>"
		});
	});
</script>
<body>
	<strong>画像直リン</strong>
	<img class="delay;params={url:'images/ongakuji.jpg',width:480,height:270,title:'音楽寺'}" src="images/loading.gif" width="16" height="16" />
	<strong>意図的に2秒待たせるPHP</strong>
	<img class="delay;params={url:'wait2seconds.php',width:480,height:270,title:'音楽寺(2秒遅れ)'}" src="images/loading.gif" width="16" height="16" />
	<strong>存在しないリンクを3回再試行</strong>
	<img class="delay;params={url:'no_longer_exists',width:480,height:270,title:'存在しないURL',retry:3}" src="images/loading.gif" width="16" height="16" />
</body>

実行結果はこんな感じ。DelayLoad デモ

軽く解説。
あらかじめjQueryがロードされていることが条件。
DOMのロードが終わった状態で、DelayLoad.init()関数を実行する。
このとき引数として置換対象クラスclass、エラー時に表示されるHTMLerror、再試行回数retryをパラメータとするオブジェクトを渡すことができる。
値を省略した場合、対象クラスは「delay」、エラーメッセージは「error」、再試行回数は1回。

DelayLoad.init({class:"mydelay",retry:3});

HTMLでは、置換パラメータをクラス指定の中に記述する。
最終的にはクラス指定した要素が画像で置き換わるので、クラス指定をするのはimgタグである必要はない。
パラメータの指定方法は 「init関数で指定したクラス名;params={……}」、前記のとおり、クラス名のデフォルトは「delay」。
paramsにはいくつかのパラメータを書くことができる。
url : 必須、読み込む画像のURL。
width : 画像を表示する横幅、省略した場合はimgタグでwidthを書かなかったときと同じ動作。
height : 画像を表示する縦幅、省略した場合はimgタグでheightを書かなかったときと同じ動作。
title : 画像のaltに設定される画像のタイトル。省略した場合はaltが出力されない。
retry : エラー時の再試行回数。init関数での指定よりも優先される。省略した場合はinit関数の設定またはデフォルト値。

<img class="delay;params={url:'images/ongakuji.jpg',width:480,height:270,title:'音楽寺'}" src="material/loading.gif" width="16" height="16" />

現時点ではIEには対応してません。
要望があればバージョンアップしたいなー。

  1. コメント 0

  1. トラックバック 0

return top