POPSブログ

jqueryで簡単なLightBoxを作る

31

  Category:  jquery2012/02/22 pops 

jqueryで簡単なLightBoxプラグインを作って見ましょう。


jqueryで簡単なLightBoxを作る


jqueryはとても簡単です。でもクロスブラウザにするにはCSSは地獄です。その辺は適当にすれば良いんです。
プラグインなど作るにあたり、全部の命令など必要では無い、ほんの少しで作れます、状況に応じ覚えれば良いのです。 CGIでBBSが引き合いに出されるように、LightBoxもいろんな操作が凝縮されていますので、jquery(JavaScript)には「定番学習素材」だと思います。LightBoxは行灯、ベッド側の明かりのような意味ですから、画像も黒いところに表示すれば明かりのようにキレイです。そんな意味合い でしょう。
極簡単なものなのでCSSは地獄ではありませんが、、。


  • jqueryはJavaScriptのライブラリですから、JavaScriptを書くことになります。
  • 構造は HTML です。
  • 大きさ、位置、色などは CSS が受け持ちます。
  • 何らかのアクション、アニメ処理は jquery が実行する。
  • LightBoxは「click」アクションを受け、HTML構造を作り画像をLoadして表示している単純なものです。
  • 終了処理は、HTML構造などを全て削除します。

つまり HTHL CSS JavaScript で構成されている訳です。


【参考】semooh.jp: jQuery日本語リファレンス



LightBoxのサンプル表示

下の画像を「クリック」ください。拡大して表示します。


下のリンクを「クリック」ください。間違いURLのため表示できません。「クリック終了」。

[間違いURL]


jQueryプラグインの書式

jQueryプラグインの書式 Defaults and Options をそのまま使用しているだけです。これでjQueryプラグインになるように出来ているのです。
他と違う処は、冒頭での変数宣言が他の人より多い。functionの置き方が少し違うこと位です。別段意味はないのですが、インデントをへらしているだけです。
書き方には個人差があります。jQueryプラグインではDefaults and Optionsを使う方は少ないようです。皆、難しい書き方のようです。

【参考】docs.jquery.com: Authoring

Defaults and Options


(function($){

  $.fn.tooltip = function(options) {

    // Create some defaults, extending them with any options that were provided
    var settings = $.extend({
      'location'         : 'top',
      'background-color' : 'blue'
    },options);

    return this.each(function() {

      // Tooltip plugin code here

    });

  };
})(jQuery);

$('div').tooltip({
  'location' : 'left'
});

使用する変数がほかに影響のないように無名関数でくくります。


(function($){})(jQuery);

$.fnで無理やり、jQueryのメソッド[関数]にしますヨ、ということです。簡単。


$.fn.プラグイン名 = function(引数) {};

それぞれの関数を実行して、お帰りなさいと言うことです。中に個人の処理を書きます。


return this.each(function() {});

引数optionsを取り込み、変数settingsに上書きする。HTML側から引数を渡す場合の書き方です。


var settings = $.extend({.........},options);

以上の処理がセットになっていますので便利。簡単にjQueryプラグインが作れます。


簡単なLightBoxの説明

このページの下方に、サンプルJS、CSSのリストがあります。その詳細を説明します。


マウスでのアクションを感知する

通常LightBox系の操作はサムネール画像などクリックされたら、作動するのが一般的です。a要素が使用されJavaScriptがオフであればそのまま画像を表示します。

.popslightboxクラスが押されたら、、{} を実行しなさいの命令です。



.popslightbox クラスはなるべく他で使用されないような独自の名前をつけています。
完全に識別される様、プラグイン作者独自の名前がつけられることが多い。
CSSでのIDなども独自の名前が多いので長くなる傾向にある、識別のためである。

$('.popslightbox').click(function(e) {

	$(this)が重要、押されたa要素そのものと思ってよい。itemsに代入します。
	itemsに代入することにより、何処ででも「現在押されたa要素」を参照できます。
	$(this)はあらゆるところで使用されますので、識別するためにも、ここで代入している。

	items=$(this);

	a要素からURLを抜き出す。

	img_url=items.attr('href');

	windowの大きさを取得。あとで画像の配置などに利用する。利用する時に取得する場合もあるし、
	変数に取り込まないで直接使用する人もいる。さまざまだ。

	win_W=$(window).width();
	win_H=$(window).height();

	Overlayを作りにいきます。
	//Overlay
	showOverlay();

	画像を表示するBOX、つまりエレメントを作ります。

	//create-html-box
	create_base();

	画像をLOADにいきます。LOADされたら表示します。

	//load-image
	imageload();

	アクションに対する決まり文句、エラーにならないように、
	「何もなし」を返す様にして問題を起こさないようにする。

	return false;

});

個人により書き方が違うし、またプラグインの目的により書かれる「処理内容」は異なる。私の場合はここを短くして、
それぞれの処理を行う関数を実行している。
$(this)は javascript の e イベントを jQueryオブジェクトに代入したものです(ここではa要素そのものと考えて良い)。そこの function 内部だけで有効です。jQueryでは、色んなところで使用されます。


Overlayを作ります

LightBoxですから、特有のOverlayを作ります。ここでは少し「手の込んだ作り」になっています。従来はもっと簡単に書いても良い。
現在のhtmlの高さの取得が正確になるようにしているだけ。Overlayの透明度もCSSの設定なしで簡単に出来る。



Overlayを作る
var showOverlay=function() {

	Overlayを削除、IEでOverlayが重なると処理がストップするバグがあるので、Overlayが無くとも
	削除し未然に防いでいる。jQueryでは無いものを削除してもエラーにはならない。

	$('#pops_lightbox_overlay').empty().remove();

	htmlの高さを取得している。jQueryでは無くjavascriptを使っている。
	あからさまにパクリコードだ。これすごく正確だ。オセワになっております。

	var html_hi=Math.max(document.body.clientHeight,document.body.scrollHeight);
	html_hi=Math.max(html_hi,document.documentElement.scrollHeight);
	html_hi=Math.max(html_hi,document.documentElement.clientHeight);

	divでOverlayを作りbodyに引っ付ける、z-indexを設定すること

	$('<div id="pops_lightbox_overlay"></div>').prependTo("body");

	出来たOverlayを変数overlay_elmに代入

	overlay_elm=$('#pops_lightbox_overlay');//Object
	overlay_elm.css({'height':html_hi,'width':'100%','display':'block'});

	Overlayがクリックされたら終了処理に行くようにアクションを設定する

	overlay_elm.click(function() {
		reset_box();
	});
};

簡単にかくなら簡略できる、ここでCSSでの透明度もfadeToで出来る


var showOverlay=function() {
	var html_hi=$('html').height();
	$('<div id="pops_lightbox_overlay"></div>').prependTo("body");
	$('#pops_lightbox_overlay').click(function() {
		reset_box();
	});
	$('#pops_lightbox_overlay').css({'height':html_hi,'width':'100%','display':'block'}).fadeTo(1,0.5);
};

$('html').height();、jQueryで、htmlの高さ取得、余り正確で無い場合あり
overlay_elmに代入していないので、終了処理でも$('#pops_lightbox_overlay')を使うこと
fadeTo(1,0.5);、jQueryで、瞬間透明度0.5にする、こちら簡単

画像を表示させるBOXを作ります

divでBOXを作りその中に<img />や、ボタン、ローデング画像を配置するだけ。



var create_base=function() {

	BOXが存在すれば削除する、通常は無いはず

	if ($('#pops_lightbox')) {$('#pops_lightbox').empty().remove();}

	BOXを作りbodyに引っ付ける

	$('<div id="pops_lightbox"><div id="pops_imgholder"><img /></div><div id="pops_lightbox_loading"></div><div id="pops_close_text" title="BOX-CLOSE">close</div></div>').prependTo("body");

	#pops_lightboxを変数items_boxに保存

	items_box=$('#pops_lightbox');

	一旦非表示にする

	imgholder_elm=$('#pops_imgholder').css({'display':'none'});
	loading=$('#pops_lightbox_loading').css({'display':'none'});
	closebtn=$('#pops_close_text').css({'display':'none'});

	初期位置中央そろえの値を計算
	center_set();

	初期の大きさ100x100BOXをCSSで位置を決める
	現在画像の大きさで単にフェードさせていますが、ここから拡大することもできます。

	items_box.css({'top':lightbox_pos_Y,'left':lightbox_pos_X,'width':lightbox_Width,'height':lightbox_Height,'display':'block'});

	BOX全体にクリックされたら終了処理に行くようにアクションを設定する

	items_box.click(function() {
		reset_box();
	});
};

HTML部分構造がわかるように書く、どちらも同じ
初期位置の状況を知るには、リンク画像のURLを間違ったURLにして「クリック」してみると、画面中央でLoading画像だけが表示されるのを確認できます。つまり、ここからBOX全体を拡大することも可能な作りになっています。勿論ここでLoading画像を押せば終了できます。
初期位置の確認は、href="photo_t91.jpg" を間違いURL、href="photo_t91x.jpg" 等としてテストしてみる。



if ($('#pops_lightbox')).....判別しない場合もあるので注意、確認して使用すること
本来の書き方は
if ($('#pops_lightbox').length)...で在る。面倒なので。

HTML構造を横に書いた場合、構造が見え難い
$('<div id="pops_lightbox"><div id="pops_imgholder"><g /></div><div id="pops_lightbox_loading"></div><div id="pops_close_text" title="BOX-CLOSE">close</div></div>').prependTo("body");

構造がわかるように書く場合1
\の前に半角スペース1個、後には何も無いこと、エラーになる

$('<div id="pops_lightbox"> \
	<div id="pops_imgholder"><img /></div> \
	<div id="pops_lightbox_loading"></div> \
	<div id="pops_close_text" title="BOX-CLOSE">close</div> \
</div>').prependTo("body");

構造がわかるように書く場合2
中に変数を取り込む場合は面倒になる
$('<div id="pops_lightbox">'+
	'<div id="pops_imgholder"><img /></div>'+
	'<div id="pops_lightbox_loading"></div>'+
	'<div id="pops_close_text" title="BOX-CLOSE">close</div>'+
'</div>').prependTo("body");

画像のLOAD

画像のLOADは、jQueryの load() でも取得できます。但し画像の寸法を取得する事が出来ません。そのために javascript の new Image()を使用している。



var imageload=function() {
	loading.css({'display':'block'});

	Imageローダーオブジェクトを作る

	imgPreloader=new Image();

	読み込み完了を知らせるonloadを設定する

	imgPreloader.onload=function() {
		loading.css({'display':'none'});

		画像の大きさを取得

		basebox_Width=imgPreloader.width;
		basebox_Height=imgPreloader.height;

		リサイズしていないフラグを立てる、リサイズ判定と実行に進む

		resize=0;
		standerdSize(basebox_Width,basebox_Height);

		画像表示に進む

		view_image();
	}

	重要、URLを代入必ず onload=function(){} を設定してから書く

	imgPreloader.src=img_url;
};

重要、通常の書き方としては、var imgPreloader=new Image() が正解であるが Opera で反応しないので(Operaの画像の表示効率化での影響)、冒頭imgPreloaderを変数宣言グローバルにして使用している。これでOKだ。
imgPreloader.src=img_url;は必ずonload=function(){}を設定後に書く事。前に書くと、onloadイベントを正確に受け取れないブラウザ(IE6)もある。その対処である。下に書くのがおそらく正式でしょう。
imgPreloaderにはエラー処理も書くことができます。現在書いてはいませんが、、


画像のフエード表示

LOADされた画像の大きさでBOXを表示、画像を単にフエード表示しているだけの構成です。



var view_image=function () {

	BOX非表示

	items_box.css({'display':'none'});

	画像BOX中央表示の計算

	center_set();

	大きさを設定する

	lightbox_Width=basebox_Width;
	lightbox_Height=basebox_Height;
	imgholder_elm.css({'width':basebox_Width,'height':basebox_Height});

	読み込んだ画像URLを<img />に設定する

	imgholder_elm.children("img").empty().attr({src:img_url});

	フエード表示実行前に画像を一旦けす

	imgholder_elm.children("img").hide();

	画像収納BOXを表示、ただし画像はまだ消えている

	imgholder_elm.css({'display':'block'});

	BOX全体を計算された位置に表示する

	items_box.css({'top':lightbox_pos_Y,'left':lightbox_pos_X,'width':lightbox_Width,'height':lightbox_Height,'display':'block'});

	画像フエード表示実行

	imgholder_elm.children("img").fadeIn(o.speed,function(){

		ボタンを表示(テキスト文字)

		closebtn.css({'display':'block'});
	});
};

attr({src:img_url})で画像のURLを挿入した場合に、フエード表示以前に、画像が一瞬表示される場合があるので、この辺の防ぎ方がポイント。画像をラップしてそちらを非表示にして、画像を欄外に移動して、など。
また、画像以外のものもHTMLで挿入できる事、ボタン等も変更できる事を理解してください。


終了処理

BOX、Overlayがクリックされたら終了処理に行くようにアクションを設定されているので。全て削除する処理である。ここでは単純に削除しているが、アニメを実行することも可能です。



var reset_box=function() {

	アニメ処理(フエード)停止、アニメの途中かの判定はしていない。エラーにはならないので判定なしでstop処理している

	items_box.stop(true);

	BOX、Overlayを削除

	items_box.empty().remove();
	overlay_elm.remove();
};

そのほかの処理の説明は略する。画像サイズのリサイズ、BOX位置取得のためスクロール値で修正しているだけである。


プラグインのjQuery実行

jQuery実行には順序と規約があります。

  • 必ずCSSを先に読み込みます。
  • jQueryを読み込み、次にプラグイン等のJSを読み込みます。
  • プラグイン等の実行命令をだします。
  • 引数を渡せる作りならば、引数を記述する。
  • 下のパスはBaserCMSの絶対パスになっています。
    標準では、css/pops-lightbox.css、 js/jquery.js 当たりでしょうか。

<link href="/main/css/pops-lightbox.css" type="text/css" />
<script type="text/javascript" src="/main/js/jquery.js"></script>
<script type="text/javascript" src="/main/js/pops-lightbox.js"></script>

<script type="text/javascript">
$(function(){
	$(document).pops_lightbox();
});
</script>

これでもOK
$(document).ready(function (){  
	$(document).pops_lightbox();
});

アイテムなどのオブジェクト保存について

大変重要なことである。通常何らかの jQuery の処理を行う際に、$('#pops_lightbox') などと対象を指定する。jQuery は「その都度その場所は何処にあるのかを調べて」指定の処理を実行している。
それを早めるためにオブジェクトとして「事前に保存」しておくと何回も同じことをする必要は無くなる。複数の「同時アニメ処理」など場合「大変有効」である。マシンの処理能力の低い場合でもスムーツにアニメできる。
但し、これは正式な「jQueryの処理」では無い、誰かが考え出した手法である。注意しなければならない事もある。


【参考】to-R: 14のjQueryベストプラクティス



事前にオブジェクト保存しておく
items_box=$('#pops_lightbox');
使用方法は通常と同じである
items_box.fadeIn(o.speed,function(){}); 保存しているので早い
$('#pops_lightbox').fadeIn(o.speed,function(){}); 遅くなる

但し、下のような複数指定は出来ない、正式なjQueryの処理ではないから
$('#pops_lightbox,#pops_box').fadeIn()...正式だから問題ない

複数指定は出来ないから、個別に処理しなければならない
var pops_lightbox=$('#pops_lightbox');
var pops_box=$('#pops_box');
pops_lightbox.fadeIn()....
pops_box.fadeIn()....

正式なjQueryの処理は、実際存在しないオブジェクトに処理してもエラーにはならない
$('#pops')..... #popsが無くともエラーにならない。

オブジェクト保存しているものが無ければエラーになるから注意
var pops=$('#pops');無いものを保存しても、ここではエラーにはならない
$('#pops')........保存オブジェクトが無いのに実行したためここでエラーになる。

有効な手段なので、よく認識して使用すること。


その他の注意点

  • IE8の振る舞いに注意。IE6どころではない「不届者」だ。
  • 複雑なCSSは自分が苦しむだけ。
  • 数をコナサナケレバ、身に付かない。
  • 色々な方法を試してみること。
  • IETesterで、IEの判別スクリプトが必ず正確とは限らない。(実際のWEBでは正確であっても)

IE8は、{'display':'none'}、プロパティ表記。この書き方で無いと認識しない。

$('#pops').css({'display':'none'});
$('#pops').css({'width':v_width}); などと

全て、このように統一する。
---------------------------------------------------------

WEBで正確にIEを判別しても
IETesterで、IEの判別スクリプトが必ず正確とは限らないので困ります。
正確に判定させるスクリプトを1つ

jQuery.browserは非推奨だが、IE判別だけは正確、種類は別判定する
//IE判定
var browserIE = 0;//IE判定
var browser_v = 0;//IE 6 7 8
if (jQuery.browser.msie) {
	browserIE = 1;
	if (navigator.userAgent.match(/MSIE (\d\.\d+)/)) {browser_v = parseFloat(RegExp.$1);}
}

IE判定
IEなら、browserIEは、1 の数値
IEの種類判定
browser_v、は 番号 6 7 8 を返す

サンプルJS、CSSのリスト


JS pops-lightbox.js サンプル

注意、speed (400-1000 位)だけ変えられますが、そのほかは未設定です。o は optionです。
早くするため余計なところは詰めています、ご了解ください。単純だから読めると思います。
書き換えなど自由です。画像パスなどは、環境に合わせてください。標準 ../images/loading.gif 当たりかな


//pops-lightbox.js
//5KB日本語
//POPS WEB KOUBOU

(function($){
jQuery.fn.pops_lightbox=function(o) {
//option
var o=$.extend({lightbox_type:'fade',speed:1000,path:'images/'},o || {});
// settings
var items;//click-item
var items_box;
var imgholder_elm,imgholder_elm,overlay_elm,close_btn,loading;
var img_url;
var imgPreloader;
var view_type='fade';
var lightbox_pos_Y,lightbox_pos_X;
lightbox_Width=100;
lightbox_Height=100;
var basebox_Width=100;
var basebox_Height=100;
var win_W,win_H,resize;

//IE判定 未使用
var browserIE = 0;//IE判定
var browser_v = 0;//IE 6 7 8
if (jQuery.browser.msie) {
	browserIE = 1;
	if (navigator.userAgent.match(/MSIE (\d\.\d+)/)) {browser_v = parseFloat(RegExp.$1);}
}

// function
var imageload=function() {
	loading.css({'display':'block'});
	imgPreloader=new Image();
	imgPreloader.onload=function() {
		loading.css({'display':'none'});
		basebox_Width=imgPreloader.width;
		basebox_Height=imgPreloader.height;
		resize=0;
		standerdSize(basebox_Width,basebox_Height);
		view_image();
	}
	imgPreloader.src=img_url;
};
var view_image=function () {
	items_box.css({'display':'none'});
	center_set();
	lightbox_Width=basebox_Width;
	lightbox_Height=basebox_Height;
	imgholder_elm.css({'width':basebox_Width,'height':basebox_Height});
	imgholder_elm.children("img").empty().attr({src:img_url});
	imgholder_elm.children("img").hide();
	imgholder_elm.css({'display':'block'});
	items_box.css({'top':lightbox_pos_Y,'left':lightbox_pos_X,'width':lightbox_Width,'height':lightbox_Height,'display':'block'});
	imgholder_elm.children("img").fadeIn(o.speed,function(){
		closebtn.css({'display':'block'});
	});
};
var showOverlay=function() {
	$('#pops_lightbox_overlay').empty().remove();
	var html_hi=Math.max(document.body.clientHeight,document.body.scrollHeight);
	html_hi=Math.max(html_hi,document.documentElement.scrollHeight);
	html_hi=Math.max(html_hi,document.documentElement.clientHeight);
	$('<div id="pops_lightbox_overlay"></div>').prependTo("body");
	overlay_elm=$('#pops_lightbox_overlay');//Object
	overlay_elm.css({'height':html_hi,'width':'100%','display':'block'});
	overlay_elm.click(function() {
		reset_box();
	});
};
var create_base=function() {
	if ($('#pops_lightbox')) {$('#pops_lightbox').empty().remove();}
	$('<div id="pops_lightbox"><div id="pops_imgholder"><img /></div><div id="pops_lightbox_loading"></div><div id="pops_close_text" title="BOX-CLOSE">close</div></div>').prependTo("body");
	items_box=$('#pops_lightbox');
	imgholder_elm=$('#pops_imgholder').css({'display':'none'});
	loading=$('#pops_lightbox_loading').css({'display':'none'});
	closebtn=$('#pops_close_text').css({'display':'none'});
	center_set();
	items_box.css({'top':lightbox_pos_Y,'left':lightbox_pos_X,'width':lightbox_Width,'height':lightbox_Height,'display':'block'});
	items_box.click(function() {
		reset_box();
	});
};
var reset_box=function() {
	items_box.stop(true);
	items_box.empty().remove();
	overlay_elm.remove();
};
function standerdSize(ldimg_W,ldimg_H) {
	var set_W=0,set_H=0;
	var scale_v=1;
	var erea_W=win_W-20;
	var erea_H=win_H-20;
	if (erea_W < ldimg_W) {
		scale_v=erea_W/ldimg_W;
		set_W=ldimg_W=Math.round(ldimg_W*scale_v);
		set_H=ldimg_H=Math.round(ldimg_H*scale_v);
		resize=1;
	}
	if (erea_H < ldimg_H) {
		scale_v=erea_H/ldimg_H;
		set_H=Math.round(ldimg_H*scale_v);
		set_W=Math.round(ldimg_W*scale_v);
		resize=1;
	} else {
		set_W=ldimg_W;set_H=ldimg_H;
	}
	basebox_Width=set_W;basebox_Height=set_H;
}
function center_set() {
	lightbox_pos_X=Math.floor(($(window).width()-basebox_Width)/2);
	lightbox_pos_Y=Math.floor(($(window).height()-basebox_Height)/2);
	var Scrollv=getScrollv();
	lightbox_pos_X +=Scrollv[0];
	lightbox_pos_Y +=Scrollv[1];
}
function getScrollv() {
	var ls=document.body.scrollLeft || document.documentElement.scrollLeft;
	var ts=document.body.scrollTop || document.documentElement.scrollTop;
	return [ls,ts];
}
//start
return this.each(function() {
	$('.popslightbox').click(function(e) {
		items=$(this);
		//img_url=items.children("a").attr('href');
		img_url=items.attr('href');
		win_W=$(window).width();
		win_H=$(window).height();
		//Overlay
		showOverlay();
		//create-html-box
		create_base();
		//load-image
		imageload();
		return false;
	});
});

};//fn.pops_lightbox END

})(jQuery);

面倒だから、JSと実行命令をまとめる。


面倒だから2つまとめる、fn.pops_lightbox側

(function($){
jQuery.fn.pops_lightbox=function(o) {

	内部略する

};

})(jQuery);

この下に実行命令を書き、JSを上書きする
$(function(){
	$(document).pops_lightbox();
});

画像 31x31



CSS pops-lightbox.css

画像は、webroot/images/ にあるとする、パスはBaserCMSの場合、/main/images/ である。
標準では、../images/loading.gif、当たりか。背景画像loading は取替え自由、そのままで中央表示。


/*pops-lightbox.css (basercms)日本語*/
#pops_lightbox_overlay{z-index:8999;position:absolute;top:0;left:0;width:100%;height:1px;background-color:#000000;opacity:0.8;filter:alpha(opacity=80);}
#pops_lightbox{z-index:9000;display:block;position:absolute;top:0;left:0;width:100px;height:100px;border:1px #333333 solid;text-align:left;background-color:#000000;overflow:hidden;}
#pops_imgholder{width:100px;height:100px;border-style:none;background-color:#000000;}
#pops_imgholder img{width:100%;height:100%;border-style:none;text-decoration:none;}
#pops_lightbox_loading{display:block;position:absolute;top:0;left:0;width:100%;height:100%;background: url("/main/images/loading.gif") no-repeat center center;background-color:none;}
#pops_close_text{display:block;position:absolute;top:1px;left:2px;width:50px;height:16px;color:#CCCCCC;text-align:center;background-color:none;cursor:pointer;}

私のLightBox系のものはこのような原型を少しアレンジしているだけです。自分なりの、1つの原型を作って見ると理解が深まります。プロでなかったら、エラーの無いものを作る事だけ目指し、余りスクリプトの書き方には拘らないほうが賢明です。自分のHPでいかに利用するかが目的ですから。


【参考】POPS: 簡単な自作LightBoxの表示

【参考】POPS: AlphaImageLoaderフィルターとIEの振る舞い



[ この記事のURL ]


タグ:jquery , LightBox , CSS

 

ブログ記事一覧

年別アーカイブ一覧



[1]