10
8

More than 5 years have passed since last update.

ページ内スクロールのメニューに現在地を表示する

Posted at
  • メニューをクリックしたらそのコンテンツにスクロールする
  • スクロールしたらそのメニューがアクティブになる

いろいろな方法があるが、HTMLもJSも記述やルールを少なく、数が変わっても楽に対応したい。
「メニューとコンテンツの数と順番が同じ」これだけ必須。(これがずれることはあまりないと思うけどw)

<ul class="menu">
    <li>メニュー1</li>
    <li>メニュー2</li>
    <li>メニュー3</li>
    <li>メニュー4</li>
</ul>
<ul class="con">
    <li>コンテンツ1</li>
    <li>コンテンツ2</li>
    <li>コンテンツ3</li>
    <li>コンテンツ4</li>
</ul>
$(function(){

var menu = $('.menu li'),
        menuLen = menu.length,
        con = $('.con li'),
        conArr = [],
        conArrLen,
        pos;
$(window).on('load resize',function(){
    for (var i=0;i<menuLen;i++) {
        pos = con.eq(i).offset().top - 10;
        conArr[i] = pos;
    }
    conArrLen = conArr.length;
});

menu.click(function(){
    var i = menu.index(this);
    pos = conArr[i];
    $('html,body').animate({'scrollTop':pos},600);
});

$(window).on('load scroll',function(){
    posCheck();
});

function posCheck(){
    var scrollPos = $(window).scrollTop();
    for(var i=0;i<conArrLen;i++){
        if(conArr[i] <= scrollPos && scrollPos < conArr[i+1]){
            menu.removeClass('active');
            menu.eq(i).addClass('active');
            break;
        }
    }
}

});

珍しく解説版

$(function(){

var menu = $('.menu li'),
        menuLen = menu.length,
        con = $('.con li'),
        conArr = [],
        conArrLen,
        pos;

//ページ読み込み完了時とウィンドウサイズ変更時にセット
$(window).on('load resize',function(){
    //コンテンツのポジションを配列に格納
    for (var i=0;i<menuLen;i++) { //メニューの数だけコンテンツのポジョションを取得
        pos = con.eq(i).offset().top - 10; //ぴったりだとUI的に良くないので少しずらす
        conArr[i] = pos;
    }
    conArrLen = conArr.length;
});

//メニューをクリックしたらそのコンテンツにスクロールする
menu.click(function(){
    var i = menu.index(this); //メニューのindexを取得
    pos = conArr[i]; //ページ読み込み完了時につくった配列から取得
    $('html,body').animate({'scrollTop':pos},600);
});

//スクロールしたらそのメニューがアクティブになる
$(window).on('load scroll',function(){
    posCheck();
});

function posCheck(){
    var scrollPos = $(window).scrollTop();
    for(var i=0;i<conArrLen;i++){
        if(conArr[i] <= scrollPos && scrollPos < conArr[i+1]){ //スクロールポジションがi番目のコンテンツとその次のコンテンツの間にあるかどうかを調べる
            menu.removeClass('active');
            menu.eq(i).addClass('active');
            break; //一致したらactiveの処理とforを終了する
        }
    }
}

});

注意すべきところは、
コンテンツのポジションを取る時に、loadの後でないと高さが違ってしまう場合がある。
というくらいでしょうか?

10
8
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
8