vue.jsscrollmodal-dialogpopupmodalpopup

(Vue.js) Scrolling in the modal will also scroll the back of the modal


Clicking on the image brings up a long, scrolling modal. The problem is that if you scrolling in the modal will also scroll the back of the modal. How do you solve it?

Modal is a component. Here is my code:

Carousel.vue

<template>
  <div>
    <div v-for="(item, index) in photos" :key="index">
      <div @click="imgClick(item)" style="cursor:pointer;">
        <img :src="item.thumbnail" />
      </div>
      <Modal v-if='item.show' @close="item.show = false">
        <div slot='body'>
          <img :src="item.thumbnail" :class="`img-index--${index}`"/>
        </div>        
      </Modal>
    </div>
  </div>
</template>

<script>
import Modal from './Modal.vue'
export default {
  props: {
    items: { type: Array, default: () => [] }
  },
  data() {
    return {
      photos: {}
    }
  },
  created() {
    this.photos = this.items.map(item => {
      return { ...item, show: false }
    })
  },
  methods: {
    imgClick(item) {
      item.show = true
    }
  },
  components: {
    Modal: Modal
  }
}
</script>


Solution

  • Most modal packages solve this by applying a class to the <body> tag when a modal is opened. For example, <body class="modal-open">. Then in your application's CSS, you can add this rule:

    body.modal-open {
      overflow: hidden;
    }
    

    This will make it so that the page behind the modal is no longer scrollable.

    Whichever modal package you are using likely fires events when the modal is opened or closed. You can apply this class to the <body> tag in the open event handler, and remove the class from the <body> tag in the close event handler.


    UPDATE

    Based on the code you added, here's how you can toggle the modal-open class on the <body> tag:

    ...
    
    <div @click="showModal(item)" style="cursor:pointer;">
      <img :src="item.thumbnail" />
    </div>
    <Modal v-if='item.show' @close="hideModal(item)">
      <div slot='body'>
        <img :src="item.thumbnail" :class="`img-index--${index}`"/>
      </div>        
    </Modal>
    
    ...
    
    {
    ...
    
    methods: {
      showModal(item) {
        item.show = true
        document.body.classList.add("modal-open");
      },
      hideModal(item) {
        item.show = false;
        document.body.classList.remove("modal-open");
      }
    },
    
    ...
    }
    

    See this jsFiddle for reference.