[MooTools Tutorial] ページのコンテンツをスライドさせて切り替える

コンテンツを全部横並びの帯状に配置して、ボタンクリックで水平方向にスライド表示させるチュートリアルです。
中身が少なくて写真で誤魔化さざるを得ないようなサイトにもってこいなアニメーション。
Coreだけで作れるのでお手軽だと思います。

View DEMO

View DEMO

Coreクラスのダウンロード方法などは省略しているので、初回のMooToolsのCoreとMoreについてをご覧ください。
なお、Step1~Step3も同じ内容となっています。

Step1:画面を作る

横並びの配置はJavaScript側で処理するので、各コンテンツは普通に縦に並べた状態でいいです。
その方がJavaScriptオフでも見れる状態になります。

pageslide2

スライドで表示するコンテンツにはそれぞれIDを振り、
ナビゲーションのhrefにはクリックした時に表示するコンテンツのIDを入れておきます。

スライドさせる要素の親となる#wrapperにはposition:relativeoverflow:hiddenを指定してください。

<body>
<div id="header">
<h1>MooTools Page-Slide Animation DEMO</h1>
	<ul id="nav">
	<li><a href="#spring" class="button">Spring</a></li>
	<li><a href="#summer" class="button">Summer</a></li>
	<li><a href="#autumun" class="button">Autumun</a></li>
	<li><a href="#winter" class="button">Winter</a></li>
</ul>
</div>
<div id="wrapper">
	<div id="spring" class="page">
		<h2>Spring</h2>
		<p><img src="images/spring.jpg" alt="" width="640" height="480" /></p>
	</div>
	<div id="summer" class="page">
		<h2>Summer</h2>
		<p><img src="images/summer.jpg" alt="" width="640" height="512" /></p>
	</div>
	<div id="autumun" class="page">
		<h2>Autumun</h2>
		<p><img src="images/autumun.jpg" alt="" width="640" height="512" /></p>
	</div>
	<div id="winter" class="page">
		<h2>Autumun</h2>
		<p><img src="images/winter.jpg" alt="" width="640" height="480" /></p>
	</div>
</div>
</body>

Step2:MooToolsのCoreを読み込む

head内にスクリプトタグを1行入れるだけです。

<script type="text/javascript" src="mootools-1.2.4-core.js"></script>

入れる場所はbodyの閉じタグ直前とかでもいいんですが、これから書くソースより前に読み込まれてないとエラーになります。

Step3:addEventでdomreadyする

Coreのスクリプトタグよりも後方に、イベントを実行するためのスターターを書きます。

<script type="text/javascript">
//<!&#91;CDATA&#91;
window.addEvent("domready",function(){

});
//&#93;&#93;>
</script>

以降のソースはこのfunction内に記述します。

Step4:必要な要素の取得

動作に必要な要素を取得して変数を定義します。

まず、ウィンドウのサイズを得るのに必要なbody。document.bodyをドル関数に入れるだけです。

var html = $(document.body);

次に、スライドさせる要素の親であるDIV#wrapper。これもドル関数

var wrapper = $("wrapper");

スライドさせる要素は#wrapperの子要素なのでgetChildrenメソッド使います。

var pages = wrapper.getChildren(); //page div

クリックイベントを付与させるためにメニューのボタンも必要です。
クラス振らずにaタグを指定してもOKです。

var nav = $("nav").getElements(".button");

横スクロールだけなのでFx.Tweenを使います。第一引数の要素には#wrapperを指定。
オプションのpropertyはleftで、linkをcancelにしておきます。
初期位置はposition:absoluteのleft:0なのでset(0)とします。

var myTween = new Fx.Tween(belt,{duration:800, property:"left",transition:Fx.Transitions.Cubic.easeInOut,link:"cancel"}).set(0);

クリックされた表示中の要素を閉まっておく入れ物を用意しておきます。
これはリサイズされたときの処理で使います。

var active = null;

Step5:コンテンツを横方向に配置する

#wrapperに高さをセットします。これは中のコンテンツを絶対配置すると高さがなくなってしまうので必須。
デモページでは#footerは絶対配置しているので、#headerを除いた高さを設定します。
ウィンドウの高さよりも縦長なら、コンテンツの高さでセットしてもいいでしょう。

wrapper.setStyle("height",html.getSize().y-50);

次にbodyにoverflowを設定して横スクロールバーを非表示にします。

html.setStyle("overflow-x","hidden");

CSSでやっつけてもいいですが、こっちで設定しておく方がjavascriptオフ対策になります。

コンテンツを1枚のベルト状に並べるには、
横幅100%のdivをコンテンツの数だけ横に配置すればいいので、
まずはbodyの横幅をgetSizeで取得します。

var width = html.getSize().x; //bodyの横幅

#wrapperの横幅を(bodyの横幅×コンテンツの数)pxにします。
コンテンツの数は変数pagesからlengthプロパティで取得。

wrapper.setStyles({"width": width * pages.length});

それから変数pagesをeachで処理し、コンテンツのdiv要素にCSSをセットしていきます。
横方向の位置は(bodyの横幅×配列のインデックス番号)で求められます。

pages.each(function(div, index){
	var pos = width * index;//left
	div.setStyles({
	 "position":"absolute",
	  "top":0,
	  "left": pos,
	  "width":width
	 });
});

これで横に配置出来たと思います。

Step6:クリックイベントの追加

ナビゲーションにクリックイベントを追加してスライドさせます。
リンクはStep4で変数navに取得しているのでそれをeachで処理します。

nav.each(function(a,index){
});

スライドさせて表示する要素は横に並んでいるんですが、リサイズされたら位置が都度変わるので
クリックしたときに対応するIDを持つ要素のleftを取得して、その位置にFx.Tweenを動かせばいいわけです。
まず先にStep5の変数pagesを処理するeachに、left位置を保存するstoreを追加します。

pages.each(function(div, index){
	var pos = width * index;//left
	div.setStyles({
	 "position":"absolute",
	  "top":0,
	  "left": pos,
	  "width":width
	 });
	div.store("pos", pos);//位置を保存
});

リンクのhrefにはIDを入れてあるので、正規表現を使えばシャープ以外の文字列を得ることが出来ます。

nav.each(function(a,index){
	var div = $(a.href.match(/#([\w]+)$/i)[1]);
});

addEventの引数にはイベントオブジェクトが入ります。
リンクが有効になってアンカージャンプしないように最初にstop()しておきます。
それからstoreで保存してあるleftプロパティ値を利用してFx.Tweenをstartさせます。
最後に、クリックして現在表示されているdiv要素を変数activeに保存しておきます。

nav.each(function(a,index){
	var div = $(a.href.match(/#([\w]+)$/i)[1]);
	a.addEvent("click",function(e){
		e.stop();
		myTween.start(0 - div.retrieve("pos"));
		active = div;
	});
});

Step7:リサイズ処理

ウィンドウサイズが変更された時に追随するようにします。

リサイズされた時に再計算しなければいけないのは

  1. bodyのサイズ
  2. #wrapperのサイズ
  3. コンテンツのサイズ
  4. コンテンツの位置(CSSのleftプロパティ)

以上の4つです。
これらはStep5でやっつけているので、該当部分を関数化すればリサイズしたときにも使えるようになります。

var sizing = function(){

	var width = html.getSize().x; //bodyの横幅
	
	wrapper.setStyles({"width": width * pages.length});
	
	pages.each(function(div, index){
		var pos = width * index;
		div.setStyles({
		 "position":"absolute",
		  "top":0,
		  "left": pos,
		  "width":width
		 });
		div.store("pos", pos);
	});
};

関数化したので、domready時に実行させるソースを1行書いておきます。

sizing();

ウィンドウサイズが変更された時=リサイズ=onResizeなので、addEventでイベントを追加します。

window.addEvent("resize",function(){ 
	sizing();
});

これだけで追随はされているんですが、
ウィンドウサイズを変更したときに表示しているコンテンツがズレるので、ついでにFx.Tweenも動かします。
表示されている要素の入れ物として変数activeを作ったので、
retrieveでleft位置を取得して移動させます。

window.addEvent("resize",function(){ 
	sizing();
	if(active) myTween.start(0 - active.retrieve("pos"));
});

Step4でFx.Tweenのインスタンスを作るときにlinkを”cancel”に設定していますが、
これはリサイズが連続で呼び出された時にFx.Tweenのアニメーションを全てキャンセルするためです。
設定していないとIEやSafariなどでおかしな感じになってしまいます。

以上で完成です。
ソース全文はデモページで確認できます

補足:小窓の中だけに表示する場合

全画面ではなく、ある要素の中だけに表示させてスライドさせることも出来ます。
その場合は#wrapperではなく、新しくスライドさせるための要素を作成する必要があります。
#wrapperを小窓にするイメージ

var belt = new Element("div",{ "id":"belt",styles:{"position":"absolute","top":0,"z-index":1}});

新しく作成した要素の中に各コンテンツを横に並べてスライドさせます。
コンテンツを入れるのはsizing関数の中で行います。

//サイズが変わったとき
var sizing = function(){
	var width = html.getSize().x; //bodyの横幅
	belt.setStyles({"width": width * pages.length});
		pages.each(function(div, index){
			var pos = width * index;
			div.setStyles({
			 "position":"absolute",
			  "top":0,
			  "left": pos,
			  "width":width
			 });
			belt.adopt(div);//要素を入れる
			div.store("pos", pos);
		});
	belt.inject(wrapper);//#wrapperの中に#beltを入れる
};

コメントを残す

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください