≫ jQueryプラグイン化した新バージョンを作成しました。
CookieをIEからFirefoxへインポートする際、ドメイン名の解釈の違いでcookieが複数生成されるバグを修正しました。(2010.03.06)
IE6,IE7でJavaScriptが動作しないバグを修正しました。(2009.09.10)
クッキー(cookie)とJavaScriptを使って、いわゆるYahoo!トピックスのタブ表示みたいなのを作ろう!という企画。
たまに使いたくなるクッキー。でも処理がめんどくさそうなので今まで敬遠してきた。
そんな折、テレビから「START!一歩を踏み出そう」の声が・・・。なんか作らないといけないような強迫観念にさいなまれて、サンプルを作成してみた。
以下、HTMLのマークアップ。(簡略化してます)
<ul id="tabhead">
<li id="head-tab0" class="on"><a id="anchor-tab0" href="#">foo_a</a></li>
<li id="head-tab1"><a id="anchor-tab1" href="#">foo_b</a></li>
<li id="head-tab2"><a id="anchor-tab2" href="#">foo_c</a></li>
</ul>
<div id="tabbody">
<div id="body-tab0" class="current">
<h2>foo_a</h2>
<ul>
<li>hoge</li>
</ul>
</div>
<div id="body-tab1">
<h2>foo_b</h2>
<ul>
<li>hoge</li>
</ul>
</div>
<div id="body-tab2">
<h2>foo_c</h2>
<ul>
<li>hoge</li>
</ul>
</div>
</div>
肝心のJavaScript部分は以下↓
//変数設定
var CookieTab = {
cookieName: 'select', //cookieに書き込むプロパティ名
cookieExpires: 10, //cookieの有効期限(単位:日)
tabHeadId: 'tabhead', //タブheadのID名
tabBodyId: 'tabbody', //タブbodyのID名
tabHdPrefix: 'head-', //タブheadリストのID接頭語
tabBdPrefix: 'body-', //タブbodyリストのID接頭語
tabAnPrefix: 'anchor-' //タブheadアンカーのID接頭語
};
//DOM読込完了後、tab制御開始
dom.event.addEventListener(window,'load',function(){
CookieTab.setting();
});
//tabの初期制御
CookieTab.setting = function() {
this.tabValue = this.getCookie(this.cookieName);
this.domAnalysis();
if(!this.tabValue || this.tabValue==undefined){
this.tabValue = 'tab0';
}
this.tabControl();
}
//cookie書込用関数
CookieTab.setCookie = function(ckName, ckValue, ckExpires, ckDomain, ckPath, ckSecure) {
var date = new Date();
date.setTime(date.getTime() + ckExpires*24*60*60*1000);
var ckStr = escape(ckName) + '=' + escape(ckValue);//日本語使用時の文字化け対策
ckStr += '; expires=' + date.toGMTString();//有効期限をGMT値に変換
if(ckDomain) {
ckStr += '; domain=' + ckDomain;
}
if(ckPath) {
ckStr += '; path=' + ckPath;
}
if(ckSecure) {
ckStr += '; secure';
}
document.cookie = ckStr;
}
//cookie取得用関数
CookieTab.getCookie = function(ckName) {
var ckMatch = ('; ' + document.cookie + ';').match('; ' + ckName + '=(.*?);');
var ckValue;
if(ckMatch){
ckValue = ckMatch[1];
} else {
ckValue = '';
}
ckValue = unescape(ckValue);//escapeしたものを元に戻す
return ckValue;
}
//DOM解析用関数
CookieTab.domAnalysis = function() {
this.linum = this.ID(this.tabHeadId).getElementsByTagName('li').length;
this.tabBdDiv = this.ID(this.tabBodyId).getElementsByTagName('div').length;
if(this.linum != this.tabBdDiv){
throw new Error('tabHead is not equal to tabBody.');
}
}
//tabの初期設定
CookieTab.tabControl = function() {
this.tabDisplay();
for(var i=0; i<this.linum; i++){
this.tabAnchor(i);//tabクリック時の動作設定
}
}
//tabの表示制御
CookieTab.tabDisplay = function() {
for(var i=0; i<this.linum; i++){
//互換性維持のためclassの取得・設定にはhoge.className = fooを使用
this.ID(this.tabHdPrefix + 'tab' + i).className = '';
this.ID(this.tabBdPrefix + 'tab' + i).className = '';
}
this.ID(this.tabHdPrefix + CookieTab.tabValue).className = 'on';
this.ID(this.tabBdPrefix + CookieTab.tabValue).className = 'current';
}
//tabクリック時の動作制御
CookieTab.tabAnchor = function(tabnum) {
this.ID(this.tabAnPrefix + 'tab' + tabnum).onclick = function(){
CookieTab.setCookie(CookieTab.cookieName,'tab' + tabnum,CookieTab.cookieExpires,location.hostname);//Cookieを発行するドメイン名を明示的に指定
CookieTab.tabValue = CookieTab.getCookie(CookieTab.cookieName);
CookieTab.tabDisplay();
return false;
}
}
//getElementByIdの短縮形を使用
CookieTab.ID = function(id) {
var myId = document.getElementById(id);
return myId;
}
解説は時間と紙面の関係上、割愛。スクリプトに少しコメントを入れてるので、そちらを参照ください。
ちょっと前から「オライリーのサイの本」を読んで、ちょこちょこ勉強してるけど、やっぱ手を動かさないとダメ。「名前空間を汚さないようにモジュール化する」ってことの意味が、やっと少し分かった気がする。
今回は「jQuery」を使わず実装したけど、jQueryを使った場合のスクリプトは以下。
jQueryにプラスして、「jquery.cookie.js」も使用するのであしからず。
//DOM読込完了後、tab制御開始
$(document).ready(function(){
CookieTab.setting();
});
//tabの初期制御
CookieTab.setting = function() {
this.tabValue = $.cookie(this.cookieName);
if(!this.tabValue || this.tabValue==undefined){
this.tabValue = 'tab0';
}
this.tabControl();
}
//tabの初期設定
CookieTab.tabControl = function() {
this.tabDisplay();
$('#' + this.tabHeadId + ' li a').each(function(value){
$(this).click(function(){//tabクリック時の動作設定
value+='';//数値型→文字列型変換
$.cookie(CookieTab.cookieName, 'tab' + value, { expires: CookieTab.cookieExpires, domain: (location.hostname) });//Cookieを発行するドメイン名を明示的に指定
CookieTab.tabValue = $.cookie(CookieTab.cookieName);
CookieTab.tabDisplay();
return false;
});
});
}
//tabの表示制御
CookieTab.tabDisplay = function() {
$('#' + this.tabHeadId + ' li').each(function(){
$(this).removeClass('on');
});
$('#' + this.tabBodyId + ' div').each(function(){
$(this).removeClass('current');
});
$('#' + this.tabHdPrefix + this.tabValue).addClass('on');
$('#' + this.tabBdPrefix + this.tabValue).addClass('current');
}
jQueryには、jQueryの難しさがあるし、こっちの方法も結構めんどい。適材適所で使うのがよいかと。
サンプルのダウンロードもできるので、興味がある方はどうぞ。
これを使う機会、いつか来るかな。
≫CookieTab.jsサンプルファイルの一括ダウンロードはこちら
ライセンス:
「クリエイティブコモンズライセンス:帰属(Attribution, by)」での公開・配布となります。
最近、ちょこちょこお世話になってるjQuery。
便利なのはいいんだけど、読み込み時間が気になる。ってことで、jQueryの機能が必要ないページで読み込むのを控えてたら、JavaScriptエラーでつまづいたので自分用にメモ。
たとえば、ロード完了時にアラートを出す以下のコード。
このケース、jQueryが読み込まれてないと、「$ってナンデスカ?」っていうエラー「$ is not defined」が発生してしまう。
ってことで、jQueryの読み込みを判別するため、以下のif文を追加した。
( サンプルページ1 / サンプルページ2 )
これでめでたくエラーとはおさらばです。
GWだし、なにか作るかってことで、フォームの入力項目を切り替える「switchform」のサンプルをアップ。
たまに実装する機会があるので、使い回せるように作ってみた。
まずは作成したswitchformのサンプルから。 (⇒ダウンロードはこちら)
使いどころとしては、会員登録フォームで「個人」か「法人」かを選んでもらう時、かな。
「個人」で登録したい人には、「会社名」とか「部署名」の入力欄を表示しない方が、ユーザビリティ的にいいんじゃないかと。
使い方は以下参照。
フォーム部分のHTML
<table id="target-form">
<thead>
<tr>
<th>種別<span>[必須]</span></th>
<td>
<ul>
<li><input type="radio" name="case" id="trigger0" value="0" /><label for="trigger0">ケース0</label></li>
<li><input type="radio" name="case" id="trigger1" value="1" /><label for="trigger1">ケース1</label></li>
<li><input type="radio" name="case" id="trigger2" value="2" /><label for="trigger2">ケース2</label></li>
</ul>
</td>
</tr>
</thead>
<tbody>
<tr class="group0">
<th><label>グループ0</label></th>
<td><input type="text" /></td>
</tr>
<tr class="group1">
<th><label>グループ1</label></th>
<td><input type="text" /></td>
</tr>
<tr class="group2">
<th><label>グループ2</label></th>
<td><input type="text" /></td>
</tr>
<tr>
<th><label>共通の項目</label></th>
<td><input type="text" /></td>
</tr>
</tbody>
</table>
「switchform」の使い方
(1) <table>のIDは、「target-form」とする。(JavaScriptで変更可能)
(2) 種別のラジオボタンには、「trigger」で始まるIDをtrigger0,trigger1のように数字で順に振る。
(3) 入力行の<tr>要素に「group」で始まる対応したclassを振る。
たとえば、ケース0で入力する項目には、「class="group0"」と指定。
(4) 共通で使用する項目の場合、入力行へのclass指定は不要。
(5) ラジオボタンを増やしたい場合は、「trigger**」と「group**」の数字を増やす。
使いまわせるよう工夫したつもりだけど、実はあんまり便利じゃないかも。
まあ、自分用だからいっか。
each関数を使って、JavaScriptを簡略化しました。(2009.06.01)
というわけで、僕の旧ポートフォリオサイト「スカイラブデザイン」をプチリニューアルしたときの話。
上がそのキャプチャで、コンテンツを変えたワケでもないし、基本デザインも変わってないんだけど、jQueryを使って少し動きを付けてみた。
実際にサイトを触ってもらえると分かると思うけど、ラベルをクリックすると、対応するコンテンツが現れたり消えたりするという、いわゆるトグルアクションをjQueryで実装してみただけ。
安易にjQueryに頼りたくないなあと思って、今まで避けてきたけど、使い方くらい知っとこうと思って今回自分のサイトで試してみた。
jQueryのトグルアクションに苦戦。
jQueryを使い慣れてる人なら、30分もかけず、このくらいの動きを実装できると思うけど、jQuery以前にJavaScriptの基本もあやふやな僕は、丸1日くらい悩んでしまった。
悩んで実装した結果を備忘録としてメモ書き。
HTMLのコード
jQueryの前に、まずはHTMLのコードから。(簡略化してます)
<html>
<body>
<div id="container">
<div id="header">ヘッダー</div>
<ul id="gnav">
<li id="gnav01"><a href="#box01">グローバルナビ1</a></li>
<li id="gnav02"><a href="#box02">グローバルナビ2</a></li>
<li id="gnav03"><a href="#box03">グローバルナビ3</a></li>
</ul>
<div id="contents">
<div id="contentsMain">
<div id="box01">コンテンツ1</div>
<div id="box02">コンテンツ2</div>
<div id="box03">コンテンツ3</div>
</div>
</div>
<div id="footer">フッター</div>
</div>
</body>
</html>
ヘッダがあってナビがあってフッターがあって、その間にコンテンツがあるという典型的なHTMLソース。ここまでは問題なかったのだが・・・。
jQueryでやったこと(概要)
jQueryでどんな操作をしたのか、コードではなく、まずはフローとして書いてみる。
1) コンテンツエリア(#contents)の表示をオフに。
CSSで非表示にするとSEO的にあれなので、JavaScript側でオフにする。
2) 全体(#container)を上下中央揃えに。
ウインドウの大きさと、コンテンツエリアを除いた全体の高さを算出し、positionを使って上下中央の位置に揃える。
3) グローバルナビ(#gnav)のクリックに応じて、対応するコンテンツを表示(トグルダウン)。
コンテンツエリアをいったん全部表示し、必要ないコンテンツの表示はオフにする。それと同時に、コンテンツの高さを算出しトグルアクションに備える。
4) トグルダウンにスムーズな動きを付ける。
3)で算出したコンテンツの高さを元に、上下中央揃えを保ったままスムーズにトグルダウンさせる。ただし、ウインドウからコンテンツがあふれる場合は、ウインドウの上辺基準に変更する。
5) グローバルナビを再度クリックした際のトグルアップ処理。
トグルアップは上記の3),4)の逆の処理を行う。で算出したコンテンツの高さを元に、上下中央揃えを保ったままスムーズにトグルダウンさせる。
6) ウインドウサイズがリサイズされた際の処理。
ウインドウを拡大・縮小した場合、上下中央揃えの処理を再度行う。
以上1)~6)の処理をjQueryで行うことにした。この辺から既に試行錯誤が始まっていた・・・。
jQueryの実装
下記のコードそのまんま。
$(function(){//$(document).ready()の短縮形
/****** 初期設定 ******/
var content = $('#contents');
var contain = $('#container');
var contmain = $('#contentsMain');
var header = $('#header');
var gnav = $('#gnav');
var footer = $('#footer');
content.css('display','none');
var opPos;
var clPos = clPositon();
contain.css('top',clPos);
/****** トリガー設定用 ******/
var gnavs = gnav.find('li[id^=gnav]');//id=gnav**が付与されたli要素を抽出
gnavs.each(function(){//gnavsのすべての要素に対して繰り返し処理実施
var selector = $(this).find("a").attr('href');//gnavsの各a要素のhref属性#hogeを取得
var box = $(selector);
$(this).toggle(
function(){//open
contmain.empty();
contmain.append(box);
opPos = opPositon();
toggleDownAction(content,contain,opPos);
},
function(){//close
clPos = clPositon();
toggleUpAction(content,contain,clPos);
}
)
});
/****** トグルアクション関数 ******/
//トグルダウン(open)
function toggleDownAction(cc,ct,op){
cc.show();
ct.animate(
{top:op}
)
}
//トグルアップ(close)
function toggleUpAction(cc,ct,cp){
cc.hide();
ct.animate(
{top:cp}
)
}
/****** 位置算出用関数 ******/
//オープン状態に取る位置を算出
function opPositon(){
getSize();
cMargin = Math.round((docHeight - 60 - hdHeight - gnHeight - ftHeight - ctHeight)/2);
if(docHeight < ctHeight){cMargin=0;}
if(cMargin < 0){cMargin=0;}
return cMargin;
}
//クローズ状態に取る位置を算出
function clPositon(){
getSize();
nMargin = Math.round((docHeight - 100 - hdHeight - gnHeight - ftHeight)/2);
if(nMargin < 0){nMargin=0;}
return nMargin;
}
//各DOM要素のサイズ取得
function getSize(){
docHeight = $(window).height();
hdHeight = header.height();
gnHeight = gnav.height();
ftHeight = footer.height();
ctHeight = content.height();
cnHeight = contain.height();
}
//ウインドウリサイズ時の処理
$(window).resize(function(){
if(content.css('display')=='none'){
currentPos = clPositon();
} else {
currentPos = opPositon();
}
contain.css('top',currentPos);
})
})
ということで、とりあえず実装できたんだけど、もう全然ダメ、俺。
jQueryの書き方がどうのこうのよりも、JavaScriptの変数の扱いが途中でよく分からなくなり、勉強不足を身にしみて感じた今回のプチリニューアル。
これを機会にオライリーのサイの本で、基礎から勉強しなおそうと思った冬の日の週末でした。
![]() | JavaScript 第5版 村上 列 オライリー・ジャパン 2007-08-14 売り上げランキング : 11884 おすすめ平均 ![]() Amazonで詳しく見る by G-Tools |
スムーズに開閉するドロップダウンメニューを作ってみた。名付けて「Waterfall Menu」。
ベースにしたのは、この Sliding JavaScript Dropdown Menu。
以前、このJavaScriptを仕事で使おうとしたんだけど、メニューの下に1pxの変な余白ができたりしたので、使うのをやめてしまった。
ということで、リベンジしたよという記事。
jsでスムーズに開閉するドロップダウンメニュー。メニューにマウスオーバすると、サブメニューが展開します。
HTMLのソースは以下。
<dl class="dropdown" title="two">
<dt id="ddheader-two">Dropdown Two</dt>
<dd id="ddcontent-two">
<ul>
<li><a href="#" class="underline">Navigation Item 1</a></li>
<li><a href="#" class="underline">Navigation Item 2</a></li>
<li><a href="#" class="underline">Navigation Item 3</a></li>
<li><a href="#" class="underline">Navigation Item 4</a></li>
<li><a href="#">Navigation Item 5</a></li>
</ul>
</dd>
</dl>
<dl class="accordion">に変更すると、下のコンテンツも連動して移動。(JavaScriptじゃなくて、CSSを変えてるだけ)。
title属性を振ってるのは、どのサブメニューが伸びるのかを指定するため。
<dl class="dropdown"> ⇒ 重なるように移動
<dl class="accordion"> ⇒ 下のコンテンツも連動して移動
<dl title="hoge"> ⇒ hogeというidが付いた<dd>が移動
実装しては見たもののHTMLのソースが全然綺麗じゃない...。
もうちょっとプレーンなソースが書けるよう努力します。
ライセンス:
「クリエイティブコモンズライセンス:帰属(Attribution, by)」での公開・配布となります。
参考記事:
[JS]軽量のスムーズに開閉するドロップダウンメニューのスクリプト | コリス
Sliding JavaScript Dropdown Menu - Web Development Blog
JavaScriptでのクロージャの使い方