👌
Vue+compositionAPIでiframe内のスクロールを検知する
はじめに
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;
}
最後にこちらのコードでスクロール量を計算し、下までスクロールした時にボタン活性化のフラグを更新します。
参考
Discussion