🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

Q&A

解決済

2回答

902閲覧

ページ内リンクでページ上部に戻る(<a href="#"></a>)ときにもスムーススクロールを適用したい

aaaaMAX

総合スコア16

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

0グッド

0クリップ

投稿2021/03/02 08:58

前提・実現したいこと

https://teratail.com/questions/325312
直接の関係はないのですが、上記で作ったリストのアンカーリンクをアドレスバーに反映しない方法を探していたところ、以下のjsを導入することで解決しました。
しかし<a href="#"></a>でページ最上部に戻ろうとするとアドレスバーに#が入るうえ、スムーススクロールさえできません。
この場合でもアドレスバーにアンカーリンクを表示させない方法とスムーススクロールを適用する方法を教えてください。

該当のソースコード

js

1var Ease = { 2 easeInOut: t => t<.5 ? 4*t*t*t : (t-1)*(2*t-2)*(2*t-2)+1 3} 4var duration = 500; 5window.addEventListener('DOMContentLoaded', () => { 6 var smoothScrollTriggers = document.querySelectorAll('a[href^="#"]'); 7 smoothScrollTriggers.forEach(function (smoothScrollTrigger) { 8 smoothScrollTrigger.addEventListener('click', function (e) { 9 var href = smoothScrollTrigger.getAttribute('href'); 10 var currentPostion = document.documentElement.scrollTop || document.body.scrollTop; 11 var targetElement = document.getElementById(href.replace('#', '')); 12 if (targetElement) { 13 e.preventDefault(); 14 e.stopPropagation(); 15 var targetPosition = window.pageYOffset + targetElement.getBoundingClientRect().top - 0; 16 var startTime = performance.now(); 17 var loop = function (nowTime) { 18 var time = nowTime - startTime; 19 var normalizedTime = time / duration; 20 if (normalizedTime < 1) { 21 window.scrollTo(0, currentPostion + ((targetPosition - currentPostion) * Ease.easeInOut(normalizedTime))); 22 requestAnimationFrame(loop); 23 } else { 24 window.scrollTo(0, targetPosition); 25 } 26 } 27 requestAnimationFrame(loop); 28 } 29 }); 30 }); 31});

試したこと

else {
window.scrollTo(0, targetPosition);
}

<a href="#"></a>のときに適用される動きではないかと考え、

else {
window.scrollTo({
top: targetPosition,
behavior: 'smooth',
});
}

と書き替えましたが希望の動きにはなりませんでした。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ベストアンサー

javascript

1<script> 2document.addEventListener('click',e=>{ 3 if([...document.querySelectorAll('[href="#"]')].includes(e.target)){ 4 e.preventDefault(); 5 window.scroll({ 6 top: 0, 7 behavior: "smooth", 8 }); 9 } 10}); 11</script> 12<style> 13.dummy{height:999px} 14</style> 15<div class="dummy">1</div> 16<a href="#">top</a> 17<div class="dummy">2</div> 18<a href="#">top</a> 19<div class="dummy">3</div> 20

投稿2021/03/02 10:24

yambejp

総合スコア116694

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

aaaaMAX

2021/03/02 10:47

申し訳ありません。通常のページ内リンクはこちらのJavaScriptで希望通りに動いたのですが、質問文に書いた自動生成リストからのページ内リンクには適用されませんでした。
yambejp

2021/03/02 11:47

> 自動生成リストからのページ内リンク ちょっと意味がわかりませんが、回答文はdocumentへの処理なので 命題がただしいなら動作するはずです
aaaaMAX

2021/03/02 12:19

本当に今回の件に直接の関係はないのですが <!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <title></title> </head> <body> <script> document.addEventListener('click',e=>{ if([...document.querySelectorAll('[href="#"]')].includes(e.target)){ e.preventDefault(); window.scroll({ top: 0, behavior: "smooth", }); } }); </script> <style> .topic{height:999px} </style> <div id="mokuji"> <h1>目次</h1> <div id="toc"></div> </div> <div class="topic" id="01"> <h2>01</h2> </div> <div class="topic" id="02"> <h2>02</h2> <a href="#">top</a> </div> <div class="topic" id="03"> <h2>03</h2> <a href="#">top</a> </div> <script> document.addEventListener('DOMContentLoaded', function () { var target_toc_id = 'toc'; var target_headline = '.topic'; var toc_contents = document.getElementById( target_toc_id ); var matches = document.querySelectorAll( target_headline ); var ul = document.createElement('ul'); matches.forEach( function (value, i) { if ( value.id === '' ) { // if tag has no id, add id value.id = i; } var li = document.createElement('li'); var a = document.createElement('a'); a.innerHTML = value.querySelector('h2').innerHTML; a.href = '#' + value.id; li.appendChild(a); ul.appendChild(li); }); toc_contents.appendChild(ul); }) </script> </body> </html> とすると自動生成されたリンクにはスムーススクロールが適用されないんです。 いくつかweb上で公開されているスムーススクロールを試したところ、今回質問文に載せたjsのみリストにも適用されたという状況です。 教えていただいたjsのほうがずっとスマートなので適用されるのであればそちらを使いたかったのですが……
yambejp

2021/03/02 12:43

a.href = '#' + value.id; 「#」単体以外のページ内リンクにもスムーススクロールしたいのですか? そうなると命題とだいぶ異なると思いますが・・
aaaaMAX

2021/03/02 12:51

すみません、誤解を招く書き方だったようです。「#idの場合は上手く動くが、#単体では上手く動かない。#idでの動きを保持したまま、#単体でも動くようにしたい」というのが質問内容でした。
yambejp

2021/03/02 13:22 編集

こんな感じで <script> document.addEventListener('click',e=>{ if([...document.querySelectorAll('[href^="#"]')].includes(e.target)){ const href=e.target.getAttribute("href"); const top=(href=="#" || document.querySelector(href)==null)?0:(window.scrollY+document.querySelector(href).getBoundingClientRect().top); e.preventDefault(); window.scroll({ top, behavior: "smooth", }); } }); </script> <style> .dummy{height:999px} </style> <div id="x1" class="dummy">[1] <a href="#x2">2</a> <a href="#x3">3</a> <a href="#x4">4</a></div> <div id="x2" class="dummy"><a href="#x1">1</a> [2] <a href="#x3">3</a> <a href="#x4">4</a></div> <div id="x3" class="dummy"><a href="#x1">1</a> <a href="#x2">2</a> [3] <a href="#x4">4</a> <a href="#">#</a></div> <div id="x4"><a href="#x2">1</a> <a href="#x2">2</a> <a href="#x3">3</a> [4] <a href="#unknown">unknown</a></div>
aaaaMAX

2021/03/02 13:52 編集

こちらでもやはりリストには適用されませんでした。 ただ、また別のjsをこのリストと併用しようとしているのですが、そちらも上手く動かないのでリスト生成のjsを改善すべきなのかもしれません。 分かりづらい質問にお付き合いいただきありがとうございました。
aaaaMAX

2021/03/02 14:07

自分のファイルをいろいろといじっていたところ、idが数字始まりのときのみスムーススクロールが適用されないことが分かりました。長々とお騒がせして申し訳ありません。本当にありがとうございました。
yambejp

2021/03/02 14:13

>idが数字始まり ああ、あるあるですね。 数字のidを利用する場合は工夫が必要です document.addEventListener('click',e=>{ if([...document.querySelectorAll('[href^="#"]')].includes(e.target)){ const href=e.target.getAttribute("href"); const target=document.querySelector('[id="'+href.substr(1)+'"]'); const top=(href=="#" || target==null)?0:(window.scrollY+target.getBoundingClientRect().top); e.preventDefault(); window.scroll({ top, behavior: "smooth", }); } });
guest

0

ページトップ付近にid="top"の要素を追加して#topにリンクを張ってみてはどうでしょうか?

投稿2021/03/02 09:08

gogoweb_ikeda

総合スコア1426

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

aaaaMAX

2021/03/02 10:49

やはり<a href="#"></a>というリンクは好ましくないのでしょうか?他に方法がなさそうならご指摘の方法を採用しようと思うのですが、可能であれば#topを増やさずに済ませたいです。
gogoweb_ikeda

2021/03/02 11:00

上の試してみたことの方針で考えるなら e.preventDefault(); e.stopPropagation(); がないので本来のリンクに移動しているんじゃないですかね。elseのあとにつけてみてください。 (ただその書き方だと#のあとに存在しないIDを指定したリンクでもトップに戻ってしまいそうですが)
aaaaMAX

2021/03/02 11:16

else { e.preventDefault(); e.stopPropagation(); window.scrollTo({ top: targetPosition, behavior: 'smooth', }); } にしてみましたが、やはり#のみのリンクには適用されませんでした。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問