LoginSignup
0
0

More than 3 years have passed since last update.

vue/composition-apiでscrollの状態を扱うComposition Functionを作った

Last updated at Posted at 2020-09-10

概要

上向きにスクロールしたときに表示して、下向きにスクロールしたら隠すフッターを表示する要件が現れたので、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

0
0
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
0
0