MoreのAssetsクラスを使うチュートリアル後編です。
前編で背景画像を1枚Assetsクラスで読み込むソースを書きましたが、
今度は背景画像を3枚読み込んでからクロスフェードで切り替えるものに変更します。
導入などの説明はすっ飛ばしてるので前編をご覧下さい。
前編までのあらすじとソース
- 使いまわす要素や値は変数に入れる
- Assetsクラスは画像や外部ファイルを読み込める便利なクラス。一枚だけ画像を読み込むときはimageメソッドを使う
- 背景用のdiv要素をElementクラスで作る
- 背景要素を挿入してからFx.Tweenでフェードインさせた
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | window.addEvent( "domready" , function (){ var ImageSrc = "bg_body.jpg" ; //背景画像のパス var container = $$( "body" )[0]; //bodyタグ container.setStyle( "background" , "url(ajax-loader.gif) no-repeat center center" ); //ローディング画像を背景に //Class Assets new Asset.image(ImageSrc,{ onload: function (){ //背景要素の作成 var bg = new Element( "div" ,{ "id" : "bg_body" , styles:{ "height" : "100%" , "min-height" : "100%" , "width" : "100%" , "background" : "url(" +ImageSrc+ ") no-repeat center center" , "position" : "absolute" , "top" :0, "left" :0, "z-index" :0 } }); container.setStyle( "background" , "none" ); //ローディング画像消す bg.inject(container.getLast(), "after" ); //body閉じタグ前に入れる var fx = new Fx.Tween(bg,{duration:2000,property: "opacity" }).set(0); //フェードアウト fx.start(1); //フェードイン }, onerror: function (){ alert( "イメージの読み込みに失敗しました" ); } }); }); |
後編では、Assets.imagesメソッドを使って複数の画像を読み込んでから、クロスフェードで切り替えるということをします。
Step1:変数の変更
複数画像を扱うのでそれにあわせて変数を変更します。
まず、読み込む画像のファイル名を配列にします。
後述しますがAssets.imagesの第一引数が配列なのでそれに合わせたものです。
1 | var ImageSrc = [ "bg_body.jpg" , "bg_body2.jpg" , "bg_body3.jpg" ]; |
今回はFx.Tweenを別の関数で呼び出さなくてはいけないので、
前編でonloadメソッドの中で定義していた変数fxを外に出して初期値を空の配列にします。
1 | var fx = []; |
こうすることで変数はグローバルになり、保存された値を他の関数内でも使用出来るようになります。
最後に、画像のインデックス番号を保存する変数を用意します。
画像をクロスフェードで切り替える際に使用します。
1 | var next = prev = 0; |
Step2: Class Asset.imagesで複数の画像を読み込む
Asset.imageをAsset.imagesに変更します。
両者の基本構文は同じですが、第一引数やイベントメソッドが少々変わります。
1 2 3 4 | var myImage = new Asset.images(source[, properties]); //source(array):画像までのパスを含む配列(文字列でも動く) //properties(object):imgタグに付与する属性やイベント(onProgress/onComplete/onError) //myImage:読み込まれた画像のIMGエレメントの配列 |
第一引数にはStep1で変更しておいた変数ImageSrcを渡します。
これだけで読み込みが開始されますが、イベントメソッドがないと何もおきません。
イベントメソッドはAsset.imageと異なっているので、次のように変更します。
onCompleteは読み込み完了後に実行されます。Asset.imageでのonloadです。
onProgressは読み込み中の画像のインデックス番号などを返すので、プログレスバーとかを作るのに役立ちます。
onErrorは画像が読み込み出来なかった場合に実行されるメソッドです。エラー表示を作ることができます。
1 2 3 4 5 6 7 8 9 10 11 12 | //Class Assets new Asset.images(ImageSrc,{ onProgress: function (counter, index){ }, onComplete: function (){ }, onError: function (){ alert( "イメージの読み込みに失敗しました" ); } }); |
上記ソースを書けば読み込み開始されるのでconsole.log()などで確認してみてください。
以降の説明は上記ソースのonCompleteメソッドの部分だけ抜き出して行います。
Step3:背景画像の要素を作成する
読み込み完了したらonCompleteメソッドが実行されるのですが、このメソッドには戻り値がありません。
そこで、画像ファイルのパスが入っている変数ImageSrcを繰り返し処理してDIV要素を作ります。
繰り返し処理といえばfor文ですが、MooToolsにはeachメソッドという便利なものがあるのでこちらを使います。
1 2 3 4 5 6 7 8 | myarray.each(fn(item, index, array)[, bind]); //fn(function):配列の各要素に対して実行される関数。この関数にはその要素自身と配列内でのインデックスが渡されます。 //bind(object/option):関数内において'this'として参照したいオブジェクト。 //item:配列内における現在の要素 //index(number):配列内における現在の要素のインデックス //array(array):実際の配列 |
($eachというのもあるんですがそれとは微妙に違います)
では上の構文に従って書いてみます。
配列に入れてあるのは画像のパスなので、引数をitemからsrcにしました。srcには文字列が入ります。
indexは配列のインデックス番号です。今回は画像が3枚なので0~2になります。
中身は前編のonload部分と殆ど同じですが、最後に作っているFx.Tweenのインスタンスを
空配列fxに保存している部分が異なります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | ImageSrc.each( function (src,index){ var bg = new Element( "div" ,{ "id" : "bg_body" +index, styles:{ "height" : "100%" , "min-height" : "100%" , "width" : "100%" , "background" : "url(" +src+ ") no-repeat center center" , "position" : "absolute" , "top" :0, "left" :0, "z-index" :0 } }); container.setStyle( "background" , "none" ); //ローディング画像消す bg.inject(container.getLast(), "after" ); //背景要素をbody閉じタグ前にinject fx[index] = new Fx.Tween(bg,{duration:2000,property: "opacity" }).set(0); //初期非表示にset }); |
このeachを抜けてから、最初の背景画像をstartメソッドでフェードインさせます。
その際、作成されたインスタンスは全て配列fxに格納されているので、インデックス番号0を指定します。
1 | fx[0].start(1); |
ここまでで前編と同じ状態になったと思います。
なお、返り値のmyImageにストックされるIMGエレメントを使う方法もあります。
その場合もeachで処理するのは変わりません。
Step4:繰り返し処理用の関数を作る
クロスフェードは、
主にこの2つの方法がありますが、今回は比較的楽な前者の方法を採ります。
最初の画像のインデックス番号が0なら、次にフェードインさせる画像のインデックス番号は1という具合です。
この「前」と「次」というキーワードはStep1で変数として定義してあるので、
前に表示していた画像をフェードアウトさせると同時に、次の画像をフェードインさせる
を
変数nextとprevを利用して表すと次の画像のようになります。
クロスフェードというと複雑そうですがソースにすれば2行で出来ます。
1 2 | fx[prev].start(0); //フェードアウト fx[next].start(1); //フェードイン |
3枚の画像をエンドレスリピートさせるためには、最後の画像になったら最初の画像に戻す必要があります。
次の画像を現す変数nextの場合は、最後の画像のインデックス番号よりも大きくなったら0に戻せばいいわけです。
これは三項演算で出来ます。
1 | next = (ImageSrc.length-1 > next ) ? next+1 : 0; |
ImageSrc.lengthは単純に配列内の要素数を表して値が3になるので1マイナスします。
前の画像を現す変数prevの場合は、nextから1マイナスすればいいのですが、マイナスし続ければ当然マイナスになるので
マイナスの値になった場合には最後の画像のインデックス番号にします。
1 | prev = (0 > next-1)? ImageSrc.length-1 : next-1; |
これらをまとめて関数にするのですが、あとで遅延実行させるために
匿名関数を変数に代入するという形をとります。
1 2 3 4 5 6 | var Repeat = ( function (){ fx[prev].start(0); //フェードアウト fx[next].start(1); //フェードイン next = (ImageSrc.length-1 > next ) ? next+1 : 0; prev = (0 > next-1)? ImageSrc.length-1 : next-1; }); |
Step4-2:delay関数で遅延実行
前々回のチュートリアルでperiodicalというのを使いましたが、
それと似たようなやつで遅延実行だけさせるdelayというメソッド(リファレンス/和訳)を使います。
構文はこちら↓
1 2 3 4 5 | var timeoutID = myFunction.delay(delay[, bind[, args]]); //delay:(number) 遅らせる時間(ミリ秒単位) //bind:(object, optional) 関数内で'this'として参照したいオブジェクト //args:(mixed, optional) 関数に渡される引数(複数の引数を渡す場合は配列にすること) |
今回はタイムアウトさせないので変数には入れません。
先ほど作ったRepeatの匿名関数に自身を実行させるようにdelayを追加します。
1 2 3 4 5 6 7 8 | var Repeat = ( function (){ fx[prev].start(0); //フェードアウト fx[next].start(1); //フェードイン next = (ImageSrc.length-1 > next ) ? next+1 : 0; prev = (0 > next-1)? ImageSrc.length-1 : next-1; Repeat.delay(5500); //5秒ちょい待って実行 }); |
Step4-3:onCompleteで繰り返し用関数を実行
これで繰り返し用の関数Repeatが出来たので、onCompleteから実行させます。
変数nextとprevの初期値を0にしたので、最初の画像をstartでフェードインしてから
nextを+1して次のインデックス番号に進めます。
その後でdelayメソッドによりRepeatを何秒か遅らせて実行します。
Repeatの中にはdelayが入っているので、ページを開いている限りクロスフェードが続きます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | onComplete: function (){ ImageSrc.each( function (src,index){ var bg = new Element( "div" ,{ "id" : "bg_body" +index, styles:{ "height" : "100%" , "min-height" : "100%" , "width" : "100%" , "background" : "url(" +src+ ") no-repeat center center" , "position" : "absolute" , "top" :0, "left" :0, "z-index" :0 } }); container.setStyle( "background" , "none" ); bg.inject(container.getLast(), "after" ); fx[index] = new Fx.Tween(bg,{duration:2000,property: "opacity" }).set(0); }); fx[0].start(1); next++; Repeat.delay(5500); }, |
以上で完成です。
IE9だと動作しないようです。どのあたりが修正点になってくるでしょうか。