2014年に制作した記事を2016/09に加筆修正(2017/04に改修)
表示されているページのURLを取得して、js(+jquery)を使っていろいろやってみたいと思います。
ナビゲーション(メニュー)に限らないのですが、わかりやすい使いどころかなーということで、ナビゲーションを想定します。
例えば、CMSやASPなどで構成しているwebページでは、そのサイト全体(もしくは一部のページグループ)で共通のナビゲーションを1ページごとに直接書き込むのではなくて、共通パーツとして単独のファイルを用意して、それぞれのページにそのパーツを呼び出して表示していたりします。
共通のパーツなので、そのままでは現在表示されているページのメニュー名を目立つように装飾したclassを個別に挿入するといったことができません。
そこで、jsでURLの文字列から対応するメニュー名を判定して、対応する箇所にclassを挿入してみようかと思います。
システムを構築しているPHPやperlなどで対処する場合もあります。
IE7/8でも動作しますが、IE7では表示が多少崩れています。
<ul class="navigation">
<li><a href="/test.html">menu1</a></li>
<li><a href="/test_2.html">menu2</a></li>
<li><a href="/test_3.html">menu3</a></li>
</ul>
※黒い部分をダブルクリックするとソースを選択できるので、コピーして使ってください。
任意のclass名をつけて、適当なナビゲーションを組んでください。リストタグを用いる必要はありません。
ASPではこれだけで一つのファイルとして保存したりします(実際にはヘッダー画像と一緒にとか、いろいろパターンがありますが)。
cssは必要な装飾をしてください。このサンプルではclass[current]に現在のページに対応するメニューの装飾を設定しました。
$(function(){
var getURL = window.location.href;//現在のページのURLを取得
var c = 0;//現在のページ番号を格納する変数
var rex = new RegExp('test_([^G]+).html','g');
if (getURL.match(rex)) c = (RegExp.$1) - 1;
$('.navigation li').eq(c).addClass('current');
});
※黒い部分をダブルクリックするとソースを選択できるので、コピーして使ってください。
各webページが[共通の名前+連番+拡張子]というファイル名の場合です。
現在のページのURLを取得して、共通の名前と拡張子の間の数字を正規表現で抽出し、変数cに格納します。
そして(0から数えて)c番目のメニューにclass[current]を追加しています。
実際はファイル名はそのページの内容にふさわしいものをつけられたり、ディレクトリで分けられていたり(一つのメニューに属するページが複数あったり)する方が普通だと思うので、下のjsコードの方が現実的かもしれません。
ナビゲーションのリンクはルート相対パスで指定してください。
$(function(){
var getPath = location.pathname;//現在のページのファイルパスを取得
var c = 0;//現在のページ番号を格納する変数
$('.navigation li a').each(function(index) {
if($(this).attr('href') == getPath) c = index; //ナビゲーションの中からパスが一致するものを探して、そのページ(インデックス)番号を取得
});
$('.navigation li').eq(c).addClass('current');
});
※黒い部分をダブルクリックするとソースを選択できるので、コピーして使ってください。
これは1メニューに対して1ファイル(ページ)が存在している場合のコードです。
ある程度の規模のwebサイトになると、1メニューに対してそれに属するページが複数あるのが普通かと思います。
たとえば、複合ECサイトなら、グローバルメニューにジャンルごとのカテゴリがあって、さらに細かく階層分けされているかと思います。
そういった場合は、たいてい一つのメニューに属するページは同じディレクトリに格納されていたりすると思うので、上記のコードに一手間加えると解決できると思います。
例えば、変数getPathの値と各ナビゲーションのhrefの値を正規表現やsplitなどを使って/(スラッシュ)で分割し、(同じ順番の)同じディレクトリが存在しているかどうかを比較してみるとか・・・いろいろ方法があるかと思われます。
ルート相対パスでリンクをはった場合はローカルで確認できないので、サーバにアップしてネット経由で確認してください。
現在のページのURLを取得できない(取得できるけど何らかの事情で利用できない)場合、class名とかid名とかで何とかしましょう。
例えば、menu1に相当するページが子ページ含め複数あって、URLをシステムで(ランダムに)吐き出していて、ディレクトリとかそういうのでも判定しづらいとか・・・事情ってのはいろいろあるかと思われます。
<div class="parent abctest">
<!--実際は外部ファイルをインクルードする部分-->
<ul class="navigation">
<li><a href="/abc/test.html">menu1</a></li>
<li><a href="/def/test.html">menu2</a></li>
<li><a href="/ghi/jk/test.html">menu3</a></li>
</ul>
<!--//実際は外部ファイルをインクルードする部分-->
</div>
※黒い部分をダブルクリックするとソースを選択できるので、コピーして使ってください。
ナビゲーション部分はインクルードされると想定して、それを親タグで囲みます。idで対処すれば簡単なのですが、ここではclass名で判定してみます。
class名なので、複数指定されている場合が多いと思うので、ここでは親タグに仮に二つclass名をいれています。複数あるうちの一つは必ず現在のページの拡張子を除くディレクトリ名+ファイル名にします(この例なら、メニュー3に対応するページのナビゲーションの親タグのclassはparent ghijktest)。
ここで付けたclass名で現在のページがどのメニューに対応しているのか判定します。複数設定したclass名のうちの何番目かも重要になってくるので、全てのページにおいて複数class名を記述する順番は統一してください。
インクルードされる部分のhtmlとcssは上と同じです。
$(function(){
var s = $('.parent').attr('class');
s = s.split(' '); //区切り文字を指定して、文字列を分割して配列に格納
$('.navigation li a').each(function(index) {
var checkPass = $(this).attr('href').replace('.html','').replace(/[\/]/g,'');
if(checkPass == s[1]) c = index;
});
$('.navigation li').eq(c).addClass('current');
});
※黒い部分をダブルクリックするとソースを選択できるので、コピーして使ってください。
ナビゲーションの親タグのclassを取得して、スペースを区切り文字としてclass名を分解して配列に格納します。
このサンプルでは2番目のclass名が判定用のクラス名なので、配列番号1(配列は0から数える)のclass名と各ナビゲーションのリンク先から/(スラッシュ)と拡張子を削除した文字列とを比較して一致するもののインデックス番号を変数cに格納します。
そして(0から数えて)c番目のメニューにclass[current]を追加しています。
ここではナビゲーションの親タグのclass名を取得しましたが、判定用のclass名をidに変えてidを取得してやれば、class名の分割という手間が不要になる分、楽かと思います。
ただ、企業によってはシステム屋さんがidを使うために、htmlコーダーに勝手にid名をつけられると困るというところもあるので、class名の取得で対処する方法をご紹介しました。
リンクがページ外にあっても、ページ内にあってもhtmlは普通にハッシュ(#)付きのリンクをはってください。
飛び先にはタブ切り替えコンテンツ(サイト内リンク)があって、通常ユーザーが切り替えないと表示されないタブ内にもアンカーがあるとします。
飛び先のタブ切り替え用のjs(jquery)のコードを書き換えます。
飛び先にジャンプしたときに該当するタブが表示されていれば、普通にアンカーに移動するので、該当するアンカーが存在するタブコンテンツを表示させるようにします。
実はタブコンテンツの外にあるアンカーにジャンプできていなかったり、いろいろ不具合があったので修正しました。
$(function(){
var getURL = location.pathname;//現在のページのファイルパスを取得
var href = getHash = window.location.hash; //現在のページのハッシュを取得
var tabNum, num;
tabSearch();
//タブ初期状態
$('.content_wrap > div:not(:eq(' + tabNum + '))').hide();
$('.content_wrap > div').eq(tabNum).find('div').show();
$('.tab_wrap li').removeClass('open');
$('.tab_wrap li').eq(tabNum).addClass('open');
goAnchor();
//ページ内のアンカーをクリックしたときの処理
$('a[href^=#anc]').click(function() {
href = getHash = $(this).attr('href');
tabSearch();
num = tabNum;
tabChange();
goAnchor();
window.history.pushState(null, null, getURL + href);
});
//ページ内をタブをクリックしたときの処理
$('.tab_wrap li').on('click', function() {
num = $('.tab_wrap li').index(this); //クリックしたタブが何番目のタブかを変数に格納
tabChange();
});
//タブ内アンカー検索 ※アンカーを設置するタグはある程度限定しておくh1~h6タグだけどか、divタグだけとか(ページ表示をもたつかせないため)
function tabSearch(){
tabNum = 0;
getHash = getHash.replace('#','');
$('.content_wrap > div').find('h1,h2,h3,div,p').each(function() {
if($(this).attr('id') == getHash) tabNum = $(this).parents('.content_wrap > div').index();
});
}
//アンカースクロール
function goAnchor(){
var speed = 500; //スクロールの速度
var target = $(href == '#' || href == '' ? 'html' : href);
var position = target.offset().top;
$(window).scrollTop(0);
$($.browser.safari ? 'body' : 'html').animate({scrollTop:position}, speed, 'swing');
return false;
}
//タブ切替
function tabChange(){
$('.content_wrap > div').hide(); //一度全てのタブコンテンツを非表示
$('.content_wrap > div').eq(num).fadeToggle(); //クリックしたタブに連動するコンテンツをfadeToggleで表示
$('.tab_wrap li').removeClass('open'); //一度全てのタブのclass[open]を削除
$('.tab_wrap li').eq(num).addClass('open'); //クリックしたタブにclass[open]を追加
}
});
※黒い部分をダブルクリックするとソースを選択できるので、コピーして使ってください。
これは1ページに1つのタブ切り替えコンテンツがあるパターンなので、複数ある場合はこれを参考に適宜書き換えてください。