JavaScript』の最近のブログ記事

ということで、「IEさん、頼むよ...」っていう話。

JavaScriptのIE用イベントハンドラ「attachEvent/detachEvent」。これを使って呼び出したイベント内では、thisがwindowと解釈される落とし穴が。

下記のイベントをIEで実行すると、どうなるか、さっそく検証。

HTML

JavaScript

ボタンのラベル「送信する」がalertで返される、かと思いきや、結果は「undefined」。
これが、IEでattachEventした関数内では、「this」がwindowオブジェクトとなってしまうってこと。
つまり、detachEventもできず、はまるので注意。

じゃあ、どう書けばいいのか。

JavaScript(修正版)

thisの代わりに「evt.srcElement」で、イベント発生元を取得すればよい。
と、ここまでがIEの話。

IE以外は、「addEventListener/removeEventListener」でイベントを制御するから、その振り分けをすればよい。クロスブラウザで動作する、最終的なコードは下記。

JavaScript(クロスブラウザ対応版)

今回、ブラウザ依存の問題に結構はまってしまったけど、イベントのバブリングフェーズとかキャプチャフェーズについて勉強できたから、許す。(←何を?)

たまにネイティブのJavaScriptを書くと、ブラウザの差異を意識しなくていい「jQuery」のありがたみが身にしみますね。。。

補足:JavaScript(detachEventできないパターン)

thisを意図通り扱うため、上記のようにcallを使う方法もある。けど、この場合、無名関数でattachするから、detachEventできないので要注意です。

(参考サイト)
JavaScript のイベントハンドラ - daily dayflower
JavaScript メモ / チップス attachEvent() と addEventListener() [ ARTEMIS ]

jQueryプラグイン jQuery cookieTab

前田かおるさんサイトのお手伝いをした際に、タブを実装することになったので、昔つくったJavaScriptを元にjQueryプラグイン化してみた。

タブにしたい要素を指定するだけという、簡単実装。いやあ、jQueryって便利ですね。ってことで、さっそく解説。

jQuery cookieTab

指定した要素をタブ化するjQueryプラグイン。クッキーを利用して、表示するタブを記憶します。

準備

必要なデータを上記よりダウンロード後、CSSとJavaScriptを読み込む。

使い方

JavaScript

タブを適用させたい要素のid(id-of-tabname)を指定し、cookieTabを実行。

HTML(準備用)

上記で指定したタブ内に、タブメニューとタブパネルを配置。
タブメニューには「class="tab-menu"」を、タブパネルには「class="tab-panel"」を付与してください。どちらもオプション設定で変更可能です。

HTML(js実行時)

アクティブなタブメニューに<li class="current">が適用されます。
デフォルト設定では、先頭のパネル(#some-tabA)を表示します。

オプション
オプション項目 デフォルト値 内容
activeTab 0 初期表示しておくタブ
tabMenuElm .tab-menu タブメニューとする要素名(#idや.class等のCSS記法にて指定)
tabPanelElm .tab-panel タブパネルとする要素名(#idや.class等のCSS記法にて指定)
cookie 使用する cookieを使用しない(false)
cookie name jcookieTab jcookieTab-(id-of-tabname) = 0 の形式で書き込み
expires 7 cookieの有効期限 [単位:日]
path (none) cookieの有効範囲:設定したページのみ有効(none), サイト全体で有効(/)etc.
secure (none) セキュアな通信時のみcookieを送信(true)
オプション指定方法
ライセンス

MITライセンスでの配布となります。

jQuery crossFader

jQueryプラグイン jQuery crossFader

盆栽教室のサイトを制作した際に、画像ギャラリーを作る必要があったので、せっかくなのでjQueryプラグイン化してみた。

フェードイン・フェードアウトするだけのシンプルな動きなので、さっと設置したい時には便利かも。ということで、さっそく解説。

jQuery crossFader

フェードイン・フェードアウトで画像を表示するjQueryプラグイン。画像をクリックすると次の画像へ遷移します。

更新履歴
  • [2011.03.17] ver0.2 ループ制御用オプションを追加
  • [2011.02.14] ver0.1 リリース
準備

必要なデータを上記よりダウンロード後、CSSとJavaScriptを読み込む。

使い方

JavaScript

ギャラリー部分のid(id-of-crossfader)を指定し、クロスフェードを実行。

HTML(画像のみの場合)

CSSを適用するため、画像の親要素(ここでは<div>)にclass="crossfader"を付与してください。
JavaScriptオフの環境では、class="active"を付与した画像が表示されます。

HTML(リンクを設定する場合)

オプション
オプション項目 デフォルト値 内容
timer 6000 切替までの待機時間 [単位:ミリ秒]
speed 1500 遷移速度(待機時間timer経過時) [単位:ミリ秒]
changeSpd 800 遷移速度(画像クリック時) [単位:ミリ秒]
random false 画像をランダム表示する(true) or しない(false)
loop true ループ表示する(true) or しない(false)
オプション指定方法
ライセンス

MITライセンスでの配布となります。

jQuery crossFader

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

これでめでたくエラーとはおさらばです。