techa1008

ROCKET NOTE

2018.06.24

JavaScriptでURLを変更せずにページ内リンクする

通常、a要素のhref属性値にハッシュ値(#〜)を指定すると、URLにハッシュ値がつき、対応したid属性を持つ要素にページ内リンクします。

この時、URLを変更しないように、JavaScriptでページ内リンクを実装してみます。

適当なHTMLを用意。ページ内リンクは上・下の2方向を試すので2つ設置し、間のダミー要素は移動したことが分かりやすいように縞模様にします。

SELECT ALL

<a href="#hoge">ページ内リンク</a>
<div style="height: 400px; background: #eee;"><!-- ダミー --></div>
<div style="height: 400px; background: #fff;"><!-- ダミー --></div>
<div style="height: 400px; background: #eee;"><!-- ダミー --></div>
<div style="height: 400px; background: #fff;"><!-- ダミー --></div>
<div style="height: 400px; background: #eee;"><!-- ダミー --></div>
<div id="hoge">目的位置</div>
<div style="height: 400px; background: #eee;"><!-- ダミー --></div>
<div style="height: 400px; background: #fff;"><!-- ダミー --></div>
<div style="height: 400px; background: #eee;"><!-- ダミー --></div>
<div style="height: 400px; background: #fff;"><!-- ダミー --></div>
<div style="height: 400px; background: #eee;"><!-- ダミー --></div>
<a href="#hoge">ページ内リンク</a>
<script>
JavaScript記述箇所
</script>

JavaScript記述箇所にコードを書きます。

SELECT ALL

// リンク要素を取得
var target_elements = document.getElementsByTagName('a');

// ひとつずつ検証
for (var i = 0; i < target_elements.length; i++){

	// ページ内リンクがある場合
	if (target_elements[i].href.indexOf('#') >= 0){

		// クリックイベント追加
		target_elements[i].addEventListener('click', function(e){

			// リンク先が存在する場合
			if (document.getElementById(e.currentTarget.hash.split('#')[1]) != null){

				// 縦位置を取得
				var goal_y = document.getElementById(e.currentTarget.hash.split('#')[1]).getBoundingClientRect().top + window.pageYOffset;

				// スムーズスクロール
				smooth_scroll(goal_y);

			}

			// リンク自体はキャンセル
			e.preventDefault();

		});

	}

}

// スムーズスクロール(目的位置)
function smooth_scroll(goal_y){

	// 今の縦スクロール位置を取得
	var current_scroll_y = window.pageYOffset;

	// スクロールの限界値を取得
	var max_scroll_y = document.documentElement.scrollHeight - document.documentElement.clientHeight;

	// ステップ
	var step = 20;

	// 目的位置より下にいる場合はステップを反転
	if (current_scroll_y > goal_y){

		step *= -1;

	}

	// アニメーション実行
	(function scroll_anim() {

		// 今の縦スクロール位置を更新
		current_scroll_y = window.pageYOffset + step;

		// 目的位置までスクロールした、あるいは限界までスクロールした
		if ((step > 0 && current_scroll_y > goal_y) || (step < 0 && current_scroll_y < goal_y) || current_scroll_y > max_scroll_y || current_scroll_y < 0){

			// 目的地にスクロール
			window.scrollTo(0, goal_y);

			// 終了
			return false;

		} else {

			// スクロール
			window.scrollTo(0, current_scroll_y);

			// ループ
			setTimeout(function(){
				scroll_anim();
			}, 1);

		}

	})();

}

どうも冗長な気がする。。

* * *