概要
上向きにスクロールしたときに表示して、下向きにスクロールしたら隠すフッターを表示する要件が現れたので、useScroll
を作成して、スクロールの向きを絶えずリアクティブに返すComposition Functionとして扱ってみました。
ソースコード
import { useWindowScroll } from '@vueuse/core'
import {
reactive,
toRefs,
watch,
} from '@vue/composition-api'
export const useScroll = () => {
const { x, y } = process.browser ? useWindowScroll() : { ...toRefs(reactive({x: 0, y: 0})) }
const state = reactive<{
isUp: boolean,
isDown: boolean
}>({
isUp: false,
isDown: false,
})
watch(y, (newY, oldY) => {
state.isUp = newY < oldY
state.isDown = newY > oldY
})
return {
x,
y,
...toRefs(state),
}
}
解説
こちらのFunctionには、vueuseというライブラリを使わせてもらっています。
composition-apiを使った、特にブラウザのネイティブAPIで扱える値に関してリアクティブに活用できるFunctionがたくさんあります。
今回はuseWindowScroll
を利用させていただきました。
これは、windowへのEvent Listenerとして、ステート管理しているスクロールの高さを変更するハンドラを登録していることによって、リアクティブに座標の値を管理できるようにしています。
composition-apiのwatchで、スクロールのy値を監視しており、変化したときの古い値との比較によって上昇中か、下降中かを判定しています。
使い方
こんな感じで書くと、スクロールの向きに応じて出たり消えたりするフッターが作れます。高さが70px決め打ちになっているのが少し悔やまれますが、Vue3でStyle周りの改善が入るらしいのでちょっとそれを心待ちにしていようと思っています。
<template>
<footer :style="footerStyle" class="sync-scroll" :class="{ appear: isUp }">
<slot />
</footer>
</template>
<script lang='ts'>
import {
computed,
defineComponent,
} from '@nuxtjs/composition-api'
import { useScroll } from '~/composables/utils/window/useScroll'
export default defineComponent({
setup() {
const scrollState = useScroll()
const footerStyle = computed(() => {
if (scrollState.isUp) {
return {
height: '70px',
}
}
return {
bottom: '-70px',
height: '70px',
}
})
return {
...scrollState,
footerStyle,
}
},
})
</script>
<style lang='scss' scoped>
@import '@/assets/css/variable.scss';
.sync-scroll {
width: 100%;
position: fixed;
bottom: -70px;
animation-name: hide;
animation-duration: .4s;
animation-timing-function: linear;
&.appear {
bottom: 0;
animation-name: appear;
animation-duration: .4s;
animation-timing-function: linear;
}
}
@keyframes appear {
0% {
bottom: -70px;
}
100% {
bottom: 0;
}
}
@keyframes hide {
0% {
bottom: 0;
}
100% {
bottom: -70px;
}
}
</style>
注意点
もとのuseWindowScroll
が、スクロールのイベントハンドラにthrottleのような処理を噛ませていないっぽくて、全てのスクロールイベントに対してハンドラを呼び出しているようです。パフォーマンスを重視するならthrottleを噛ませたほうが良いと思います。
最後に
composition-apiにハマって日々いろいろ試して発信しているTwitterアカウントはこちらです。
https://twitter.com/Meijin_garden