WEBLOG

JavaScript > oo_lib.js

navCurrent(jQuery で nav の現在位置にクラス付与)

Create:

Update:

Category:JavaScriptoo_lib.js

Series:jQuery 独自プラグイン「oo_lib」

概要

弊社で標準プラグインとして設置するjQueryプラグイン(独自)「oo_lib.js」。

その中の「navCurrent」を紹介します。

機能

自動で、nav 内の現在位置にclass属性「current」を付与します。

画像は、現在「/service/a/?type=c」というパラメータ付きページが表示されている時にメニューのプルダウンが開かれた状態。

例えば、グローバルメニューでクラスが付与されるのは、上記の2か所になります。

ファイル構成

  • プラグイン本体 js(弊社では「oo_lib.js」 ※ base.min.js にバンドル)
  • プラグイン実行 js(弊社では「base.js」 ※ base.min.js にバンドル)

プラグイン本体

全て独自開発です。

jQuery.fn.navCurrent = function (config) {
	const opt = jQuery.extend(
		{
			ganv: true,
			submenuCurrent: true,
			submenuWrapClass: 'submenu_wrap'
		},
		config
	);
	let $links = [],
		$tempLinks = [],
		$link = {},
		$navWap = $(this),
		$navHome = $navWap.find('a[data-nav="home"]').not('a[data-navcurrent="false"]'),
		currentHref,
		run,
		i;

	// home
	if ($navHome.length > 0) {
		$links.push({
			dom: $navHome,
			link: removeDomain($navHome.attr('href')),
			home: true,
			sub: []
		});
	}
	// home,false,sub以外抽出
	$navWap
		.find('a')
		.not('a[data-nav="home"], a[data-navcurrent="false"], +  + a')
		.each(function () {
			if ($(this).attr('href') !== undefined) {
				$link = {};
				$link.dom = $(this);
				$link.link = removeDomain($(this).attr('href'));
				$link.home = false;
				$link.sub = [];
				if ($(this).parent().hasClass(opt.submenuWrapClass)) {
					$(this)
						.next()
						.find('a[href]')
						.each(function () {
							$link.sub.push($(this));
						});
					// hrefを文字列の長い順にsort *長いものほど階層が下
					$link.sub.sort(function (a, b) {
						return removeDomain(b.attr('href')).length - removeDomain(a.attr('href')).length;
					});
				}
				$tempLinks.push($link);
			}
		});
	// hrefを文字列の長い順にsort *長いものほど階層が下
	$tempLinks.sort(function (a, b) {
		return b.link.length - a.link.length;
	});
	$.merge($links, $tempLinks);

	/* match判定 */
	currentHref = removeDomain(location.href);
	run = true;
	// nav home判定
	labelAll: for (let i = 0; i < $links.length; i++) {
		if ($links[i].home) {
			if (checkMatch(currentHref, $links[i].link)) {
				$links[i].dom.addClass('current');
				run = false;
				break labelAll;
			}
		}
	}
	// submenu完全一致のみ判定
	if (run) {
		labelAll: for (i = 0; i < $links.length; i++) {
			if (!$links[i].home && $links[i].sub.length > 0) {
				for (let j = 0; j < $links[i].sub.length; j++) {
					if (checkMatch(currentHref, removeDomain($links[i].sub[j].attr('href')))) {
						if (opt.ganv) $links[i].dom.addClass('current');
						if (opt.submenuCurrent) $links[i].sub[j].addClass('current');
						run = false;
						break labelAll;
					}
				}
			}
		}
	}
	// submenu前方一致判定
	if (run) {
		labelAll: for (i = 0; i < $links.length; i++) {
			if (!$links[i].home && $links[i].sub.length > 0) {
				for (j = 0; j < $links[i].sub.length; j++) {
					if (checkPreMatch(currentHref, removeDomain($links[i].sub[j].attr('href')))) {
						if (opt.ganv) $links[i].dom.addClass('current');
						if (opt.submenuCurrent) $links[i].sub[j].addClass('current');
						run = false;
						break labelAll;
					}
				}
			}
		}
	}
	// nav完全一致判定
	if (run) {
		labelAll: for (i = 0; i < $links.length; i++) {
			if (!$links[i].home && checkMatch(currentHref, removeDomain($links[i].link))) {
				$links[i].dom.addClass('current');
				run = false;
				break labelAll;
			}
		}
	}
	// nav前方一致判定
	if (run && opt.ganv) {
		labelAll: for (i = 0; i < $links.length; i++) {
			if (!$links[i].home && checkPreMatch(currentHref, removeDomain($links[i].link))) {
				$links[i].dom.addClass('current');
				run = false;
				break labelAll;
			}
		}
	}
	/* func */
	// gnav リンクを正規化した上で配列生成(homeリンク除く)
	function removeDomain(href) {
		if (href === undefined) {
			return;
		}
		let m = href.match(/^(http)*s*:?\/\/[a-zA-Z0-9-.]+(.*)$/);
		if (m) {
			return m[2] === '' ? '/' : m[2];
		} else {
			return href;
		}
	}
	// 前方一致
	function checkPreMatch(string, pattern) {
		if (string.indexOf(pattern) === 0) {
			return true;
		} else {
			return false;
		}
	}
	// 完全一致
	function checkMatch(string, pattern) {
		if (string === pattern) {
			return true;
		} else {
			return false;
		}
	}
	return this;
};

使い方

下記を記述すると .nav クラス属性の箇所での動作します。

js
$('.nav').navCurrent();

// オプション設定付き
$('.nav').navCurrent({
	submenuCurrent: true,
	ganv: true,
	submenuWrapClass: 'submenu_wrap'
});

下記のオプション値が使用できます。

  • submenuCurrent:サブメニューのクラス付与(default=true)
  • gnav:サブメニューがマッチしたときに親にクラス付与(default=true)
  • submenuWrapClas:サブメニューを含む li のラッパークラス
html
<ul class="nav">
	<li><a href="/" data-nav="home">HOME</a></li>
	<li class="submenu_wrap">
		<a href="/service/">SERVICE</a>
		<ul>
			<li><a href="/service/">SERVICE</a></li>
			<li><a href="/service/a/">A</a></li>
			<li><a href="/service/a/?type=c">A-typeC</a></li>
			<li><a href="/faq/">FAQ</a></li>
		</ul>
	</li>
	<li><a href="/company/">COMPANY</a></li>
</ul>
補足

※ 本サイトでも使用しています。

弊社のコーディングに合わせて作ったものですので、li li a の箇所など合わないマークアップがあるかもしれません。

pagetop
loading