Vue.jsを用いて画面を開いたタイミングでモーダル表示をするように実装しています。
モーダル内ではスクロールを可能にし、背景はスクロールしないようにしたいのですが、うまくいかないためご教授いただければと思います。
試したこと
JavaScriptのtouchmoveとwheelで制御することでモーダル表示の時に背景となるメイン画面がスクロールしないように実装をしようと試みました。
モーダル表示時に画面全体を覆うような薄い黒色の背景をつける都合上、JavaScriptの処理自体は行われてもスクロールができてしまいます。
該当のコードは以下の通りです。
メイン画面
vue
1<template> 2 <div> 3 <Modal v-if="isModal" @closeModal="closeModal" @stop="stop"/> 4 <div class="hello" ref="main"> 5 <button @click="stop()">ストップ</button> 6 <button @click="start()">スタート</button> 7 <button @click="openModal()">ダイアログ開く</button> 8 <p> 9 For a guide and recipes on how to configure / customize this project,<br> 10 check out the 11 <a href="https://cli.vuejs.org" target="_blank" rel="noopener">vue-cli documentation</a>. 12 </p> 13 <h3>Installed CLI Plugins</h3> 14 <ul> 15 <li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-babel" target="_blank" rel="noopener">babel</a></li> 16 <li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-eslint" target="_blank" rel="noopener">eslint</a></li> 17 </ul> 18 <h3>Essential Links</h3> 19 <ul> 20 <li><a href="https://vuejs.org" target="_blank" rel="noopener">Core Docs</a></li> 21 <li><a href="https://forum.vuejs.org" target="_blank" rel="noopener">Forum</a></li> 22 <li><a href="https://chat.vuejs.org" target="_blank" rel="noopener">Community Chat</a></li> 23 <li><a href="https://twitter.com/vuejs" target="_blank" rel="noopener">Twitter</a></li> 24 <li><a href="https://news.vuejs.org" target="_blank" rel="noopener">News</a></li> 25 </ul> 26 <h3>Ecosystem</h3> 27 <ul> 28 <li><a href="https://router.vuejs.org" target="_blank" rel="noopener">vue-router</a></li> 29 <li><a href="https://vuex.vuejs.org" target="_blank" rel="noopener">vuex</a></li> 30 <li><a href="https://github.com/vuejs/vue-devtools#vue-devtools" target="_blank" rel="noopener">vue-devtools</a></li> 31 <li><a href="https://vue-loader.vuejs.org" target="_blank" rel="noopener">vue-loader</a></li> 32 <li><a href="https://github.com/vuejs/awesome-vue" target="_blank" rel="noopener">awesome-vue</a></li> 33 </ul> 34 </div> 35 </div> 36</template> 37 38<script> 39import Modal from "@/components/modal.vue" 40export default { 41 components: { 42 Modal 43 }, 44 data() { 45 return { 46 isModal: false, 47 } 48 }, 49 methods: { 50 handleTouchMove(event) { 51 event.preventDefault(); 52 }, 53 stop() { 54 const main = this.$refs.main; 55 main.addEventListener('touchmove', this.handleTouchMove, { passive: false }); 56 main.addEventListener('wheel', this.handleTouchMove, { passive: false }); 57 }, 58 start() { 59 const main = this.$refs.main; 60 main.removeEventListener('touchmove', this.handleTouchMove, { passive: false }); 61 main.removeEventListener('wheel', this.handleTouchMove, { passive: false }); 62 }, 63 closeModal() { 64 this.isModal = false 65 }, 66 openModal() { 67 this.isModal = true 68 } 69 }, 70 mounted() { 71 this.$nextTick(() => { 72 this.openModal() 73 }) 74 } 75} 76</script>
モーダル
vue
1<template> 2 <div> 3 <div class="modal-bg d-flex justify-content-center h-100 w-100 align-items-center position-fixed" 4 @click.self="clickCloseBtn()" ref="modal"> 5 <div class="bg-white contents" ref="contents"> 6 <p class="mb-2">ダイアログ</p> 7 <p class="mb-2">ダイアログ</p> 8 <p class="mb-2">ダイアログ</p> 9 <p class="mb-2">ダイアログ</p> 10 </div> 11 </div> 12 </div> 13</template> 14 15<script> 16export default { 17 methods: { 18 clickCloseBtn() { 19 this.$emit('closeModal') 20 }, 21 }, 22 mounted() { 23 this.$nextTick(() => { 24 this.$emit('stop') 25 }) 26 } 27} 28</script> 29<style> 30.modal-bg { 31 top:0; 32 left:0; 33 background-color:rgba(0,0,0,0.5); 34 z-index: 10; 35} 36 37.modal-bg .contents { 38 z-index:20; 39 width:80%; 40 height: 10%; 41 overflow: auto; 42} 43</style>
よく方法として目にする
「モーダル表示前のスクロール位置を取得→モーダル表示のタイミングでposition:fixedを設定し、topに先ほど取得したスクロール位置を設定」
といった方法も試したのですが、今回のような画面を開いた時にスクロール位置を取得する場合iPhoneのSafariではスクロール位置の取得がうまくできず、setTImeoutで位置取得の処理を遅らせるといった方法を取ることになりそうです。
どれくらいの時間遅らせるかといった当たりをつけて実装をするのはベストとは言えないと考えています。
実装としては以下のようになるイメージです。
vue
1this.$nextTick(() => { 2 window.scrollTo(0,scrollHeight); 3 setTimeout(function() { 4 this.scrollPosition = window.scrollY; //ここで取得したスクロール位置をtopに設定する 5 this.isModal = true 6 }, 500) 7})
あなたの回答
tips
プレビュー