3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

アルサーガパートナーズAdvent Calendar 2021

Day 8

Vue+compositionAPIでiframe内のスクロールを検知する

Last updated at Posted at 2021-12-07

はじめに

webアプリでよく見る利用規約を下までスクロールするとボタンが活性化し、同意できる機能を実装したい

コード全体

<template>
  <div class="container">
    <div class="content">
      <div class="term-of-use-container">
        <iframe
          class="term-of-use"
          ref="termOfUseRef"
          src="/term_of_use.html"
          frameborder="0"
        />
      </div>
      <div class="button-container">
        <button
          class="button color-orange"
          :class="{ 'color-gray': isDisabled }"
          :disabled="isDisabled"
          @click="onClickButton"
        >
          同意する
        </button>
      </div>
    </div>
  </div>
</template>
<script lang="ts">
import { defineComponent, ref, onMounted } from "vue";

export default defineComponent({
  setup() {
    const termOfUseRef = ref<HTMLIFrameElement>();
    const isDisabled = ref<boolean>(true);

    const onClickButton = () => alert("同意しました!");

    onMounted(() => {
      termOfUseRef.value?.contentWindow?.addEventListener("scroll", () => {
        if (!termOfUseRef.value) return;
        if (!termOfUseRef.value.contentWindow) return;
        const scrollAdjustmentValue = 50;
        // テキスト全体の高さ
        const scrollHeight =
          termOfUseRef.value.contentDocument?.documentElement.scrollHeight || 0;
        // スクロール量
        const scrollAmount = termOfUseRef.value.contentWindow.scrollY || 0;
        // ウィンドウ(表示される枠)の高さ
        const windowHeight = termOfUseRef.value.contentWindow.innerHeight || 0;

        if (
          scrollAmount + windowHeight + scrollAdjustmentValue >
          scrollHeight
        ) {
          isDisabled.value = false;
        }
      });
    });

    return {
      termOfUseRef,
      isDisabled,
      onClickButton,
    };
  },
});
</script>
<style scoped>
.container {
  display: flex;
  justify-content: center;
  width: 100vw;
  height: 100vh;
}
.content {
  margin-top: 50px;
  margin-bottom: 50px;
}
.term-of-use {
  width: 500px;
  height: 500px;
}
.button-container {
  display: flex;
  justify-content: center;
  margin-top: 20px;
}
.button {
  width: 200px;
  color: #fff;
  border-radius: 100vh;
}
.color-orange {
  background-color: orange;
}
.color-gray {
  background-color: gray;
}
</style>

解説

<iframe
  class="term-of-use"
  ref="termOfUseRef"
  src="/term_of_use.html"
  frameborder="0"
/>

vueテンプレート内にref="termOfUseRef"のようにテンプレート参照を付与します。

const termOfUseRef = ref<HTMLIFrameElement>();

setup関数内で参照の変数を定義します。このとき変数名はテンプレート内に記述したref="termOfUseRef"と同じ名前にします。

onMounted(() => {
  termOfUseRef.value?.contentWindow?.addEventListener("scroll", () => {
    // 省略
  });
});

onMounted内でイベントリスナを呼び出しスクロールイベントを検知します。
ポイントはcontentWindowの部分で、これによりiframe内のDOMにアクセスすることができます。そこでイベントリスナを呼び出すことでiframe内のスクロールを検知することができます。

const scrollAdjustmentValue = 50;
// テキスト全体の高さ
const scrollHeight =
  termOfUseRef.value.contentDocument?.documentElement.scrollHeight || 0;
// スクロール量
const scrollAmount = termOfUseRef.value.contentWindow.scrollY || 0;
// ウィンドウ(表示される枠)の高さ
const windowHeight = termOfUseRef.value.contentWindow.innerHeight || 0;

if (
  scrollAmount + windowHeight + scrollAdjustmentValue >
  scrollHeight
) {
  isDisabled.value = false;
}

最後にこちらのコードでスクロール量を計算し、下までスクロールした時にボタン活性化のフラグを更新します。

参考にさせていただきました

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

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?