Vue.jsのv3(Composition API)でスクロールすると出てくる「トップへ戻る」ボタンの作り方を紹介します。
仕組みは3つだけです。scrollイベントでwindow.scrollYを監視し、一定量スクロールしたらrefの真偽値を切り替えてボタンのclassを付け外しします。クリック時はwindow.scrollTo({ top: 0, behavior: 'smooth' })で先頭に戻ります。ライブラリは不要で、アイコンだけBoxiconsを使います。
Vue 3で「トップへ戻る」ボタンの作り方
index.html
アイコンを使いたいので、今回はBoxiconsを使用します。
<html lang="">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<link href='https://unpkg.com/boxicons@2.0.7/css/boxicons.min.css' rel='stylesheet'>
<title><%= htmlWebpackPlugin.options.title %></title>
</head>
publicフォルダのindex.htmlのheadタグ内にlinkを差し込みます。
この方法か、npmを使う方法があります。
上のindex.htmlはVue CLIで作ったプロジェクトのものです。Viteで作ったプロジェクトではindex.htmlがプロジェクト直下にあり、<%= BASE_URL %>のような記法は使いません。その場合もlinkタグを同じようにheadに置けば動きます。
template
<template>
<a
href="#"
class="scrolltop"
@click="scrollTop"
:class="{'show-scroll' : scrollHeader}">
<i class='bx bxs-chevron-up scrolltop__icon' ></i>
</a>
</template>
templateタグでは、Boxiconsより取得したiタグのアイコンフォントをaタグで囲ってリンクにします。
aタグでは、scrollHeaderがtrueのときshow-scrollクラスが付与されるように動的なclassを作成します。
この動的なクラスで、一定のところまでスクロールしたときにスクロールトップのボタンを表示させます。
クリックしたときに上へ戻るようにするためにscrollTopというメソッドを指定しておきます。
また、iタグではアイコンの装飾をしています。
script
<script>
import { onMounted, ref } from 'vue';
export default {
setup() {
const scrollHeader = ref(false)
function showScrollTop() {
if(window.scrollY >= 560) {
scrollHeader.value = true
} else {
scrollHeader.value = false
}
}
function scrollTop() {
if(window.scrollY >= 560) {
window.scrollTo({
top: 0,
behavior:'smooth'
})
}
}
onMounted(() => {
window.addEventListener("scroll", showScrollTop, { passive: true })
})
return {
scrollTop,
scrollHeader,
showScrollTop,
}
}
}</script>
onMountedとrefを使うので、vueからimportします。
setup内では、true/falseのscrollHeaderを定義します。
一定のところまでスクロールされたら表示したい場合、window.scrollYでその値を取得できます。
window.scrollYは、ページの一番上からどれだけ縦にスクロールしたかをピクセル数で返します。
コンソールなどでよい位置を確認して設定します。
上の例では560としています。
560以上ならscrollHeaderをtrueに(上へ戻るボタンを表示)、そうでないならfalse(非表示)にする関数を作成します。
そして、スクロールするには、window.scrollToを使います。
topからの位置を指定します。一番上に戻りたい場合は0を指定します。
behaviorでは、smoothを指定するとスルスルとなめらかに動きます。
そして、mountされたときにスクロールを検知できるよう、onMountedでイベントリスナーを設定します。
{ passive: true }にすると、リスナー内でpreventDefault()を使わないことをブラウザに伝えられます。
ブラウザは画面描写を待たずにスクロールを処理できるので、カクつき防止にも有効です。
コンポーネントが破棄されてもリスナーは自動では外れないので、ページ遷移のあるアプリではonUnmountedで解除しておきます。<script setup>で書き直すと次のようになります。
<script setup>
import { onMounted, onUnmounted, ref } from 'vue'
const scrollHeader = ref(false)
function showScrollTop() {
scrollHeader.value = window.scrollY >= 560
}
function scrollTop() {
window.scrollTo({ top: 0, behavior: 'smooth' })
}
onMounted(() => {
window.addEventListener('scroll', showScrollTop, { passive: true })
})
onUnmounted(() => {
window.removeEventListener('scroll', showScrollTop)
})
</script>
<script setup>ではreturnが不要で、定義した変数と関数をそのままtemplateから参照できます。
スクロール位置ではなく「特定の要素が画面に入ったか」で表示を切り替えたい場合は、scrollイベントよりIntersectionObserverのほうが軽く済みます。書き方はVue.jsで要素がスクロール画面に現れたらアニメーションさせる方法を参考にしてください。
style
<style lang="scss" scoped>
.scrolltop {
position: fixed;
right: 1rem;
bottom: -20%;
display: flex;
justify-content: center;
align-items: center;
padding: .5rem;
background-color: rgba(123,111,113,.7);
border-radius: .5rem;
z-index: var(--z-tooltop);
transition: .4s;
visibility: hidden;
&:hover {
background-color: var(--first-color);
}
&__icon {
font-size: 2rem;
color: var(--first-color-lighten);
}
}
.show-scroll {
visibility: visible;
bottom: 1.5rem;
}</style>
show-scrollで上へ戻るボタンの表示・非表示を制御しているので、visibilityを操作します。
下から出てくるような簡単なトランジションを加えるなら、表示時と非表示時のbottomに違う値を設定します。
アイコンフォントではなくSVGを使いたい場合はtailwindcssでSVGアイコンを使う方法、スクロール量そのものを可視化したい場合はライブラリを使わずに進捗バーを表示する方法が同じ考え方で作れます。