リンクまわりの小技(URL取得と文字列操作) [jQuery] [js]

2014年に制作した記事を2016/09に加筆修正(2017/04に改修)

表示されているページのURLを取得して、js(+jquery)を使っていろいろやってみたいと思います。


sample(現在のページのナビゲーションの表示状態を変える)

ナビゲーション(メニュー)に限らないのですが、わかりやすい使いどころかなーということで、ナビゲーションを想定します。

例えば、CMSやASPなどで構成しているwebページでは、そのサイト全体(もしくは一部のページグループ)で共通のナビゲーションを1ページごとに直接書き込むのではなくて、共通パーツとして単独のファイルを用意して、それぞれのページにそのパーツを呼び出して表示していたりします。

共通のパーツなので、そのままでは現在表示されているページのメニュー名を目立つように装飾したclassを個別に挿入するといったことができません。
そこで、jsでURLの文字列から対応するメニュー名を判定して、対応する箇所にclassを挿入してみようかと思います。

システムを構築しているPHPやperlなどで対処する場合もあります。

IE7/8でも動作しますが、IE7では表示が多少崩れています。


html

<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]に現在のページに対応するメニューの装飾を設定しました。


js

$(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コードの方が現実的かもしれません。


js(webページのファイル名がバラバラのとき)

ナビゲーションのリンクはルート相対パスで指定してください。

$(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などを使って/(スラッシュ)で分割し、(同じ順番の)同じディレクトリが存在しているかどうかを比較してみるとか・・・いろいろ方法があるかと思われます。

ルート相対パスでリンクをはった場合はローカルで確認できないので、サーバにアップしてネット経由で確認してください。


sample(URLは参考にできない場合)

現在のページのURLを取得できない(取得できるけど何らかの事情で利用できない)場合、class名とかid名とかで何とかしましょう。

例えば、menu1に相当するページが子ページ含め複数あって、URLをシステムで(ランダムに)吐き出していて、ディレクトリとかそういうのでも判定しづらいとか・・・事情ってのはいろいろあるかと思われます。

html

<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は上と同じです。


js

$(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名の取得で対処する方法をご紹介しました。


sample(リンク先のタブ切り替えの中のアンカーにジャンプ)


html

リンクがページ外にあっても、ページ内にあってもhtmlは普通にハッシュ(#)付きのリンクをはってください。

飛び先にはタブ切り替えコンテンツ(サイト内リンク)があって、通常ユーザーが切り替えないと表示されないタブ内にもアンカーがあるとします。


js(改修版)・・・2017/04加筆修正

飛び先のタブ切り替え用の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. 2行目:現在のページのファイルパスを取得して、変数getURLに格納
  2. 3行目:現在のページのURLからハッシュを取得して、変数hrefとgetHushに格納
  3. 4行目:その他、あとで記述する関数で使用するグローバル変数を宣言
  4. 6~30行目:ページが表示されたときやページ内のアンカーやタブがクリックされたときの処理
  5. 33~57行目:ページが表示されたときやページ内のアンカーやタブがクリックされたときに実行される共通の処理を関数にしておく
  6. 33~39行目:タブ内アンカー検索の関数tabSearch()を設定
  7. 34行目:タブ番号(変数tabNum)の初期値を0にしておく
  8. 35行目:現在のページのハッシュを格納しておいたgetHushから#を削除
  9. 36~38行目:getHushの値と一致するidを有しているタグを探し、その親タグのインデックス番号を変数tabNumに格納(これがアンカーリンクのとび先があるタブ番号)
  10. 42~49行目:ページ内のアンカーリンクをスムーズにスクロールさせる関数goAnchor()を設定。詳細はjQueryでスムーススクロール(サイト内リンク)参照
    ここでは常にページの一番上からアンカーへスクロールするように$(window).scrollTop(0);を追加
  11. 52~57行目:ページ内のタブがクリックされたとき表示を切り替える関数tabChange()を設定。詳細はタブ切り替えコンテンツ(サイト内リンク)参照
  12. 6行目:ページが表示されたとき、関数tabSearch()を実行して、一度タブ番号を格納する変数tabNumをリセットし、アドレスバーのURLに#があれば、その後の文字列と一致するidが存在するタブのタブ番号を検索する。
  13. 9~12行目:ページが表示されたとき(ページ外からアンカーリンクをクリックして表示したとき)のタブ初期状態を設定。
    6行目のtabSearch()で検索したタブ番号に該当するタブを表示する(tabNum番目以外を非表示にする)。
  14. 14行目:ページが表示されたとき、関数goAnchor()を実行して、ページ内アンカーがあれば、該当箇所へスクロールさせる。
  15. 17~24行目:ページ内のアンカーリンクがクリックされたときの処理(関数tabChange()と関数goAnchor()を実行)
    jQueryでスムーススクロール(サイト内リンク)ではアドレスバーのurlが書き換えられないので、アンカーへ移動後、ページの再読込をしたりブラウザの戻るボタンを使用した際に、ユーザーが期待するであろうページ遷移にならない。
    そこで、history.pushStateをつかってアドレスバーのurlの書き換えも行う。
  16. 27~30行目:ページ内のタブがクリックされたときの処理(関数tabChange()を実行)

これは1ページに1つのタブ切り替えコンテンツがあるパターンなので、複数ある場合はこれを参考に適宜書き換えてください。

  • タブコンテンツ内の全てのタグに対して、変数getHushと一致するアンカーを検索するのは大変なので、アンカーを設置するタグをある程度限定しておくと良いかと思います。
  • タブコンテンツ内のアンカーにジャンプしたとき、場合によってはタブ部分がウィンドウの表示外にあるために、それがタブ切替えコンテンツと気づかれない可能性があります。そのページにアンカー部分以外の情報もあることをユーザーに意識して欲しい場合は、何らかの工夫が必要です。
    ここでは常にページの一番上からアンカーへスクロールするようにすることで、タブが一瞬見えるようにしてみましたが、同じタブ内でのアンカーへの移動の時もいちいちページトップからのスクロールになるので、ページが長いとうざいかもしれません。
    気になるようであれば、同じタブ内での移動はスクロールの開始位置を現在の位置からになるように条件式を加えてみたり、工夫してください。
  • URLの末尾に?をくっつけて何やら値を付与するクエリ文字列を使うなど、解決方法はこれに限りません。


戻る

Top