👆

【Vue】規約を最下部までスクロールしないと押せないチェックボタン

2023/01/04に公開

2023/01/27追記

新しくscrollendというイベントが追加されました。
本記事の方法を使わなくてもscrollendイベントを使って、より簡単にスクロールの終わりを検知することができそうです!

https://developer.chrome.com/en/blog/scrollend-a-new-javascript-event/

与件

  • 利用規約への同意画面がモーダルで表示される
  • 規約文章を最下部までスクロールしないと同意のチェックボタンが押せない

コード

template

<div class="modal-panel">
  <div ref="reference" class="scroll-area">
    <!-- 利用規約文章 -->
  </div>
  <div class="agreement">
    <checkbox
      v-model="isChecked"
      :disabled="!isScrollDown"
    />
    <span>利用規約に同意する</span>
  </div>
</div>

script

import { defineComponent, ref, onMounted } from '@nuxtjs/composition-api'

export default defineComponent({
  setup () {
    const isScrollDown = ref(false)
    const reference = ref(null)
    
    onMounted(() => {
      reference.value.onscroll = function () {
        const clientHeight = reference.value.clientHeight
        const scrollHeight = reference.value.scrollHeight

        if (scrollHeight - (clientHeight + reference.value.scrollTop) < 1) {
          isScrollDown.value = true
        }
      }
    })

    return {
      isScrollDown,
      reference
    }
  }
})

解説

Vue.jsのライフサイクルフックであるonMountedを使用しています。onMountedは、コンポーネントがマウントされた後に実行されるフックです。

そこで、onMountedのコールバック関数内で、.onscroll関数を定義しています。これは、スクロールイベントを監視するための関数です。referenceの参照にはref属性を使用しています。

https://qiita.com/soicchi/items/82714c3f773fc5bb397f

.clientHeightは、要素の高さを取得します。
同様に.scrollHeightは、要素全体のスクロールアウトされた(隠れた)部分も含めた高さを取得します。
引用:https://ja.javascript.info/size-and-scroll#ref-3788
そして、.scrollTopは、要素の隠された部分の高さを取得します。(つまり、scrollTopは“どのくらいスクロールされているか”)
引用:https://ja.javascript.info/size-and-scroll#ref-3789

これらを使用して、ユーザーがスクロール要素の末尾に到達したかどうかを検出します。

// 隠された部分も含めた高さ - (表示されている規約文章の高さ + スクロールされた高さ) < 1 の場合
if (scrollHeight - (clientHeight + reference.value.scrollTop) < 1) {
    isScrollDown.value = true
}

もしページの末尾に到達した場合、isScrollDownをtrueに設定します。
チェックボタンには:disabled="!isScrollDown"が設定されているのでisScrollDownがtrueになるとdisabledが解除されるといった仕組みです。

Discussion