タブの処理を自作する

タブを作成する機会が度々あるので、汎用的に使いまわせるようなタブの処理を作成してみます。

サンプルコード

まずはHTMLですが、data属性を使ってタブのボタンとコンテンツを紐づけるようにします。
タブ切り替えのボタンにdata-tab-switch、タブのコンテンツにdata-tab-contentを設定します。

<div class="tab-switch">
  <div class="tab-switch_item is-open" data-tab-switch="tab-a">タブA</div>
  <div class="tab-switch_item" data-tab-switch="tab-b">タブB</div>
  <div class="tab-switch_item" data-tab-switch="tab-c">タブC</div>
</div>

<div data-tab-content="tab-a">
  <p>タブAの内容です。</p>
</div>
<div data-tab-content="tab-b">
  <p>タブBの内容です。</p>
</div>
<div data-tab-content="tab-c">
  <p>タブCの内容です。</p>
</div>

ページアクセス時に開いておきたいタブのボタン(今回の場合タブA)に.is-openを付与しています。

次にCSSですが、data属性の要素にclass(.is-open)を付けて表示が切り替わるようにします。

 
.tab-switch {
	display: flex;
}
.tab-switch_item {
	margin: 10px;
	cursor: pointer;
}

[data-tab-switch].is-open {
	color: red;
}
[data-tab-content] {
	display: none;
}
[data-tab-content].is-open {
	display: block;
}

最後にJavaScriptです。
初期表示の設定と、タブのボタンクリック時のclassの付け替えの処理を実装します。

var tabSwitchOpenClass = "is-open";
var tabContentsOpenClass = "is-open";

$(function() {
	// 初期表示の設定
	$('[data-tab-content]').removeClass(tabContentsOpenClass);
	for (var i = 0; i < $('[data-tab-content]').length; i++) {
		var target = $('[data-tab-content]').eq(i).data('tabContent');
		if($('[data-tab-switch = ' + target + ']').hasClass(tabSwitchOpenClass)) {
			$('[data-tab-content]').eq(i).addClass(tabContentsOpenClass);
			break;
		}
	}

	// タブ切り替え
	$('[data-tab-switch]').on('click', function(e) {
		var target = $(this).data('tabSwitch');
		tab_change(target);
	});
});

// タブ切り替えの処理
function tab_change(target) {
	$('[data-tab-switch]').removeClass(tabSwitchOpenClass);
	$('[data-tab-switch = ' + target + ']').addClass(tabSwitchOpenClass);
	$('[data-tab-content]').removeClass(tabContentsOpenClass);
	$('[data-tab-content = ' + target + ']').addClass(tabContentsOpenClass);
}

6〜13行目で初期表示の設定、16〜19,23〜28行目でタブ切り替えの処理を行っています。
タブ切り替えのデモページ

タブのボタンがコンテンツの下にもあるような、ボタンが複数ある場合でも動作は問題ありません。

<div class="tab-switch">
  <div class="tab-switch_item is-open" data-tab-switch="tab-a">タブA</div>
  <div class="tab-switch_item" data-tab-switch="tab-b">タブB</div>
  <div class="tab-switch_item" data-tab-switch="tab-c">タブC</div>
</div>

<div data-tab-content="tab-a">
  <p>タブAの内容です。</p>
</div>
<div data-tab-content="tab-b">
  <p>タブBの内容です。</p>
</div>
<div data-tab-content="tab-c">
  <p>タブCの内容です。</p>
</div>

<div class="tab-switch">
  <div class="tab-switch_item is-open" data-tab-switch="tab-a">タブA</div>
  <div class="tab-switch_item" data-tab-switch="tab-b">タブB</div>
  <div class="tab-switch_item" data-tab-switch="tab-c">タブC</div>
</div>

タブのボタンが複数ある場合のデモページ
 

特定のページからのアクセスの場合のみタブの初期表示を変えたいということがあるので、パラメータを設定することでタブの初期表示を変更できるようにしてみます。
HTMLとCSSは前のサンプルから変更ありません。

var tabSwitchOpenClass = "is-open";
var tabContentsOpenClass = "is-open";

$(function() {
	var tabParam = get_tab_param();

	// タブのパラメータがついている時の対応
	if($('[data-tab-content="' + tabParam + '"]').length > 0) {
		$('[data-tab-switch]').removeClass(tabSwitchOpenClass);
		$('[data-tab-switch="' + tabParam + '"]').addClass(tabSwitchOpenClass);
	}

	// 初期表示の設定
	$('[data-tab-content]').removeClass(tabContentsOpenClass);
	for (var i = 0; i < $('[data-tab-content]').length; i++) {
		var target = $('[data-tab-content]').eq(i).data('tabContent');
		if($('[data-tab-switch = ' + target + ']').hasClass(tabSwitchOpenClass)) {
			$('[data-tab-content]').eq(i).addClass(tabContentsOpenClass);
			break;
		}
	}

	// タブ切り替え
	$('[data-tab-switch]').on('click', function(e) {
		var target = $(this).data('tabSwitch');
		tab_change(target);
	});
});

// URLのパラメータ取得
function get_tab_param() {
	var params = [];
	var param = location.search.substring(1).split('&');
	for(var i = 0; i < param.length; i++) {
	  params[i] = param[i].split('=');
	}
	for(var i = 0; i < params.length; i++) {
		if(params[i][0] === 'tab' &&  params[i][1] !== undefined) {
			return params[i][1];
		}
	}
	return false;
}

// タブ切り替えの処理
function tab_change(target) {
	$('[data-tab-switch]').removeClass(tabSwitchOpenClass);
	$('[data-tab-switch = ' + target + ']').addClass(tabSwitchOpenClass);
	$('[data-tab-content]').removeClass(tabContentsOpenClass);
	$('[data-tab-content = ' + target + ']').addClass(tabContentsOpenClass);
}

30〜43行目がパラメータからタブに関する部分を取得する処理で、5〜11行目で該当するタブのボタンにclassを付け替えるようにしています。
デフォルトの状態のデモページ
「?tab=tab-c」のように、パラメータで「tab=XXX」の形でXXXに開きたいタブのdata属性の値を設定することで初期表示を設定できます。
タブCを開くデモページ
 

同一ページにタブを複数設置する場合

前述のサンプルだと同一ページ内に1つ下タブを設置できないので、複数のタブを設置できるようにしてみます。
HTMLは基本的には前述のサンプルと同じですが、data-tab-switchやdata-tab-contentを囲う要素にdata-tab-groupを追加します。

<div data-tab-group="tab1">
  <div class="tab-switch">
    <div class="tab-switch_item is-open" data-tab-switch="tab1-a">タブ1-A</div>
    <div class="tab-switch_item" data-tab-switch="tab1-b">タブ1-B</div>
    <div class="tab-switch_item" data-tab-switch="tab1-c">タブ1-C</div>
  </div>

  <div data-tab-content="tab1-a">
    <p>タブ1-Aの内容です。</p>
  </div>
  <div data-tab-content="tab1-b">
    <p>タブ1-Bの内容です。</p>
  </div>
  <div data-tab-content="tab1-c">
    <p>タブ1-Cの内容です。</p>
  </div>
</div>

<hr>

<div data-tab-group="tab2">
  <div class="tab-switch">
    <div class="tab-switch_item is-open" data-tab-switch="tab2-a">タブ2-A</div>
    <div class="tab-switch_item" data-tab-switch="tab2-b">タブ2-B</div>
    <div class="tab-switch_item" data-tab-switch="tab2-c">タブ2-C</div>
  </div>

  <div data-tab-content="tab2-a">
    <p>タブ2-Aの内容です。</p>
  </div>
  <div data-tab-content="tab2-b">
    <p>タブ2-Bの内容です。</p>
  </div>
  <div data-tab-content="tab2-c">
    <p>タブ2-Cの内容です。</p>
  </div>
</div>

このdata-tab-group内が1つのタブになります。

次にJavaScriptです。

var tabSwitchOpenClass = "is-open";
var tabContentsOpenClass = "is-open";

$(function() {
	// 初期表示の設定
	$('[data-tab-content]').removeClass(tabContentsOpenClass);
	for (var i = 0; i < $('[data-tab-group]').length; i++) {
		var $thisGroup = $('[data-tab-group]').eq(i);
		for (var j = 0; j < $thisGroup.find('[data-tab-content]').length; j++) {
			var target = $thisGroup.find('[data-tab-content]').eq(j).data('tabContent');
			if($thisGroup.find('[data-tab-switch = ' + target + ']').hasClass(tabSwitchOpenClass)) {
				$thisGroup.find('[data-tab-content]').eq(j).addClass(tabContentsOpenClass);
				break;
			}
		}
	}

	// タブ切り替え
	$('[data-tab-switch]').on('click', function(e) {
		var group = $(this).parents('[data-tab-group]').data('tabGroup');
		var target = $(this).data('tabSwitch');
		tab_change(group, target);
	});
});

// タブ切り替えの処理
function tab_change(group, target) {
	var $thisGroup = $('[data-tab-group = ' + group + ']');
	$thisGroup.find('[data-tab-switch]').removeClass(tabSwitchOpenClass);
	$thisGroup.find('[data-tab-switch = ' + target + ']').addClass(tabSwitchOpenClass);
	$thisGroup.find('[data-tab-content]').removeClass(tabContentsOpenClass);
	$thisGroup.find('[data-tab-content = ' + target + ']').addClass(tabContentsOpenClass);
}

基本的な処理の仕組みは前のサンプルと同じですが、タブの設定をdata-tab-group毎に行うようにしています。
タブを複数設置するデモページ

最後に複数のタブで初期表示を変更できるようにしてみます。

var tabSwitchOpenClass = "is-open";
var tabContentsOpenClass = "is-open";
var tabParamPrefix = 'tab-';

$(function() {
	var tabParam = get_tab_param();
	// タブのパラメータがついている時の対応
	for (var i = 0; i < tabParam.length; i++) {
		var $thisGroup = $('[data-tab-group="' + tabParam[i][0] + '"]');
		if($thisGroup.length > 0) {
			if($thisGroup.find('[data-tab-content="' + tabParam[i][1] + '"]').length > 0) {
				$thisGroup.find('[data-tab-switch]').removeClass(tabSwitchOpenClass);
				$thisGroup.find('[data-tab-switch="' + tabParam[i][1] + '"]').addClass(tabSwitchOpenClass);
			}
		}
	}

	// 初期表示の設定
	$('[data-tab-content]').removeClass(tabContentsOpenClass);
	for (var i = 0; i < $('[data-tab-group]').length; i++) {
		var $thisGroup = $('[data-tab-group]').eq(i);
		for (var j = 0; j < $thisGroup.find('[data-tab-content]').length; j++) {
			var target = $thisGroup.find('[data-tab-content]').eq(j).data('tabContent');
			if($thisGroup.find('[data-tab-switch = ' + target + ']').hasClass(tabSwitchOpenClass)) {
				$thisGroup.find('[data-tab-content]').eq(j).addClass(tabContentsOpenClass);
				break;
			}
		}
	}

	// タブ切り替え
	$('[data-tab-switch]').on('click', function(e) {
		var group = $(this).parents('[data-tab-group]').data('tabGroup');
		var target = $(this).data('tabSwitch');
		tab_change(group, target);
	});
});

// URLのパラメータ取得
function get_tab_param() {
	var params = [];
	var param = location.search.substring(1).split('&');
	for(var i = 0; i < param.length; i++) {
	  params[i] = param[i].split('=');
	}
	var tabParams = [];
	for(var i = 0; i < params.length; i++) {
		if(!params[i][0].indexOf(tabParamPrefix) &&  params[i][1] !== undefined) {
			tabParams[tabParams.length] = [params[i][0].slice(tabParamPrefix.length), params[i][1]];
		}
	}
	if(tabParams.length > 0) {
		return tabParams;
	} else {
		return false;
	}
}

// タブ切り替えの処理
function tab_change(group, target) {
	var $thisGroup = $('[data-tab-group = ' + group + ']');
	$thisGroup.find('[data-tab-switch]').removeClass(tabSwitchOpenClass);
	$thisGroup.find('[data-tab-switch = ' + target + ']').addClass(tabSwitchOpenClass);
	$thisGroup.find('[data-tab-content]').removeClass(tabContentsOpenClass);
	$thisGroup.find('[data-tab-content = ' + target + ']').addClass(tabContentsOpenClass);
}

パラメータの設定方法を「?tab-AAA=BBB」のように変更しています。
AAAにdata-tab-groupの値、BBBに開きたいタブのdata-tab-switchの値を設定することで、初期表示を設定できます。
デフォルトの状態のデモページ
タブ1-Bとタブ2-Cを開くデモページ
 

このエントリーをはてなブックマークに追加

関連記事

コメントを残す

メールアドレスが公開されることはありません。
* が付いている欄は必須項目です

CAPTCHA


コメントが承認されるまで時間がかかります。

2024年11月
 12
3456789
10111213141516
17181920212223
24252627282930