こんにちは。前回から引き続き、
基本のタブメニュー
ウェブアプリでよく使われるインタフェースのひとつ、
<div class="js-tabs">
<ul id="tab_menu1" class="tab_menu">
<li><a href="#page1-1">Page 1</a></li>
<li><a href="#page1-2">Page 2</a></li>
<li><a href="#page1-3">Page 3</a></li>
</ul>
<div id="tab_content1" class="tab_content">
<div id="page1-1" class="page">
Page 1
</div>
<div id="page1-2" class="page">
Page 2
</div>
<div id="page1-3" class="page">
Page 3
</div>
</div>
</div>
そして、
.js-tabs ul.tab_menu{
list-style-type:none;
margin:0px;
padding:0px;
}
.js-tabs ul.tab_menu li{
display:inline;
background:#666;
margin:0px;
padding:2px;
}
.js-tabs .tab_menu li a{
padding:3px;
}
.js-tabs .tab_menu li a:link,
.js-tabs .tab_menu li a:visited{
background-color:#666;
color:#fff;
}
.js-tabs .tab_menu li a.active:link,
.js-tabs .tab_menu li a.active:visited{
background-color:#444;
color:#fff;
}
.js-tabs .tab_menu li a:hover{
background-color:#333;
color:#f0f;
}
.tab_content{
position:relative;
height:200px;
}
.tab_content div.page{
width:450px;
height:200px;
position:absolute;
color:#222;
}
#page1-1{
background-color:#ffa;
}
#page1-2{
background-color:#faf;
}
#page1-3{
background-color:#aff;
}
さて、
(function(){
var menu = document.getElementById('tab_menu1');
var content = document.getElementById('tab_content1');
var menus = menu.getElementsByTagName('a');
var current; // 現在の状態を保持する変数
for (var i = 0, l = menus.length;i < l; i++){
tab_init(menus[i], i);
}
function tab_init(link, index){
var id = link.hash.slice(1);
var page = document.getElementById(id);
if (!current){ // 状態の初期化
current = {page:page, menu:link};
page.style.display = 'block';
link.className = 'active';
} else {
page.style.display = 'none';
}
link.onclick = function(){
current.page.style.display = 'none';
current.menu.className = '';
page.style.display = 'block';
link.className = 'active';
current.page = page;
current.menu = link;
return false;
};
}
})();
タブを切り替えるには、
なお、
上記コードにおいて、
つまり、
function (){
var current;
function (){ // #1
var page, link;
function(){
// onclick
}
}
function (){ // #2
var page, link;
function(){
// onclick
}
}
function (){ // #3
var page, link;
function(){
// onclick
}
}
}
変数pageとlinkがそれぞれ3つ存在する点がポイントです。
クロージャーの復習はこれくらいにして、
機能的には問題ありませんが、
これを回避する方法はいくつかあり、
または、
というわけで、
<div class="js-tabs">
<ul id="tab_menu1" class="tab_menu">
<li><a href="#page1-1"> Page 1
</a></li><li><a href="#page1-2"> Page 2
</a></li><li><a href="#page1-3"> Page 3
</a></li>
</ul>
<div id="tab_content1" class="tab_content">
<div id="page1-1" class="page">
Page 1
</div>
<div id="page1-2" class="page">
Page 2
</div>
<div id="page1-3" class="page">
Page 3
</div>
</div>
</div>
タブメニューのアニメーション
さて、
まず、
<div class="js-tabs3">
<ul id="tab_menu3" class="tab_menu">
<li><a href="#page3-1"> Page 1
</a></li><li><a href="#page3-2"> Page 2
</a></li><li><a href="#page3-3"> Page 3
</a></li>
</ul>
<div id="tab_content3" class="tab_content">
<div id="tab_content_inner3" class="tab_content_inner">
<div id="page3-1" class="page">
Page 1
</div>
<div id="page3-2" class="page">
Page 2
</div>
<div id="page3-3" class="page">
Page 3
</div>
</div>
</div>
</div>
CSSも概ね同じですが、
さらに、
.tab_content{
position:relative;
height:200px;
width:450px;
overflow:hidden;
}
.tab_content_inner{
position:absolute;
height:200px;
width:1350px;
overflow:auto;
}
.tab_content div.page{
width:450px;
height:200px;
position:absolute;
top:0px;
color:#222;
}
#page3-1{
background-color:#ffa;
left:0px;
}
#page3-2{
background-color:#faf;
left:450px;
}
#page3-3{
background-color:#aff;
left:900px;
}
最後にJavaScriptで450px動かすようにするだけです。とてもシンプルですね。
(function(){
var menu = document.getElementById('tab_menu3');
var inner = document.getElementById('tab_content_inner3');
var menus = menu.getElementsByTagName('a');
var current;
for (var i = 0, l = menus.length;i < l; i++){
tab_init(menus[i], i);
}
function tab_init(link, index){
if (!current){
current = link;
link.className = 'active';
}
link.onclick = function(){
current.className = '';
link.className = 'active';
current = link;
inner.style.left = -450 * index + 'px';
return false;
};
}
})();
あとは、
(function(){
var menu = document.getElementById('tab_menu4');
var inner = document.getElementById('tab_content_inner4');
var menus = menu.getElementsByTagName('a');
var current;
for (var i = 0, l = menus.length;i < l; i++){
tab_init(menus[i], i);
}
function tab_init(link, index){
if (!current){
current = {menu:link, index:index};
link.className = 'active';
}
link.onclick = function(){
current.menu.className = '';
link.className = 'active';
current.menu = link;
new MiniTweener(inner.style, {
left:{
from: current.index * -450,
to: -450 * index,
suffix:'px'
}
}, {duration:300});
current.index = index;
return false;
};
}
})();
タブメニューの汎用化
ここまで、
まず、
.js-tabs5 .tab_content{
position:relative;
overflow:hidden;
}
.js-tabs5 .tab_content_inner{
position:absolute;
overflow:auto;
}
.js-tabs5 .tab_content div.page{
position:absolute;
top:0px;
color:#222;
}
#page5-1{
background-color:#ffa;
width:450px;
height:150px;
}
#page5-2{
background-color:#faf;
width:400px;
height:200px;
}
#page5-3{
background-color:#aff;
width:350px;
height:250px;
}
あとはJavaScriptで各pageごとのサイズを取得し、
要素のサイズを取得するにはclientHeight, clientWidthを用います。ほかにgetBoundingClientRectメソッドを利用するという方法もあります。getBoundingClientRectは要素のサイズや位置情報をまとめて取得できる便利なメソッドです。元々IEが独自に実装したメソッドでCSSOM View Moduleで標準化されており、
var menu = document.getElementById('tab_menu5');
var content = document.getElementById('tab_content5');
var inner = document.getElementById('tab_content_inner5');
var menus = menu.getElementsByTagName('a');
var current,
width = 0, // innerの幅
height = 0; // innerの高さ
var lefts = []; // 各要素のleft値を記憶するための配列
for (var i = 0, l = menus.length;i < l; i++){
tab_init(menus[i], i);
}
inner.style.width = width + 'px';
function tab_init(link, index){
var id = link.hash.slice(1);
var page = document.getElementById(id);
page.style.left = width + 'px';
page.style.top = '0px';
lefts[index] = width;
width += page.clientWidth;
if (height < page.clientHeight) {
height = page.clientHeight;
inner.style.height = 20 + height + 'px';
}
if (!current) {
current = {menu:link, index:index};
link.className = 'active';
content.style.width = width + 'px';
content.style.height = height + 'px';
}
link.onclick = function(){
current.menu.className = '';
link.className = 'active';
current.menu = link;
// 中身にあわせてcontentのサイズを修正
content.style.width = page.clientWidth + 'px';
content.style.height = page.clientHeight + 'px';
// 記憶しておいた位置を使って移動させる
new MiniTweener(inner.style, {
left:{
from: -lefts[current.index],
to: -lefts[index],
suffix:'px'
}
}, {duration:300});
current.index = index;
return false;
};
}
})();
まとめ
今回はJavaScriptを使ったUIとしてタブメニューの作り方を取り上げました。こういったUIはまだまだつくり込む余地がたくさんあります。是非、
次回も引き続きJavaScriptを使ったクロスブラウザなUIの実装を見ていきたいと思います。