目次

Modal Dialog

要求

Code

ModalContainer.js
import { ref, reactive } from 'https://cdnjs.cloudflare.com/ajax/libs/vue/3.0.2/vue.esm-browser.js';
 
const ModalContainer = {
  template: `
  <component is="style">
  .modal {
    display: none;
  }
  .modal-backdrop {
    z-index: 0;
    background: rgba(0, 0, 0, 0.4);
  }
  /* vueのtransitionを使わないなら不要 */
  .fade-enter-active, .fade-leave-active {
    transition: opacity .15s;
  }
  .fade-enter, .fade-leave-to {
    opacity: 0;
  }
  </component>
  <transition name="fade">
  <div v-if="visible">
    <div class="modal" tabindex="-1" :style="display_mode">
      <div class="modal-backdrop show" @click="hide"></div>
      <div class="modal-dialog" :class="size">
        <div class="modal-content">
          <div class="modal-header">
            <slot name="header">
              <button type="button" class="close" @click="hide"><span>×</span></button>
              <h5 class="modal-title">{{ title }}</h5>
            </slot>
          </div>
          <div class="modal-body">
            <slot name="body">
              <p>Modal body text goes here.</p>
            </slot>
          </div>
          <div class="modal-footer">
            <slot name="footer">
              <button type="button" class="btn btn-default" @click="hide">Close</button>
              <button type="button" class="btn btn-primary">Save changes</button>
            </slot>
          </div>
        </div>
      </div>
    </div>
  </div>
  </transition>
  `,
  props: {
    enableBackdrop: { type: Boolean, default: true },
    title:          { type: String,  default: '' },
    size:           { type: String,  default: 'modal-sm' }
  },
  setup(props, context) {
    const visible = ref(false)
    const display_mode      = reactive({display: 'none'})
    let scrollbarWidth      = 0;
    let orgBodyPaddingRight = 0;
    // let orgBodyPosition   = 'relative';
 
    function show() {
      scrollbarWidth      = window.innerWidth - document.body.clientWidth;
      orgBodyPaddingRight = document.body.style.paddingRight;
      // orgBodyPosition     = document.body.style.position;
      // document.body.style.position = 'fixed';
      if (scrollbarWidth ) {
        document.body.style.paddingRight = `${scrollbarWidth }px`;
      }
      // document.body.style.position  = 'fix';
      document.body.style.height    = '100vh';
      document.body.style.overflowY = 'hidden';
      visible.value                 = true;
      display_mode.display          = 'block';
    }
    function hide(event) {
      if (event && event.target.classList.contains('modal-backdrop') && !props.enableBackdrop) return;
      if (scrollbarWidth ) {
        document.body.style.paddingRight = orgBodyPaddingRight;
      }
      // document.body.style.position = orgBodyPosition;
      document.body.style.height    = 'auto';
      document.body.style.overflowY = 'auto';
      visible.value                 = false;      
      display_mode.display          = 'none';
    }
    return {
      visible,
      display_mode,
      show,
      hide
    }
  }
};
export default ModalContainer;

Props

Slots

Events

Demo

Bootstrap バージョンよる記述の違い調査

BS5 の実装

<div class="modal" tabindex="-1">
  <div class="modal-dialog">
    <div class="modal-content">
      <div class="modal-header">
        <h5 class="modal-title">Modal title</h5>
        <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
      </div>
      <div class="modal-body">
        <p>Modal body text goes here.</p>
      </div>
      <div class="modal-footer">
        <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
        <button type="button" class="btn btn-primary">Save changes</button>
      </div>
    </div>
  </div>
</div>

BS4 の実装

<div class="modal fade" id="exampleModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
  <div class="modal-dialog" role="document">
    <div class="modal-content">
      <div class="modal-header">
        <h5 class="modal-title" id="exampleModalLabel">Modal title</h5>
        <button type="button" class="close" data-dismiss="modal" aria-label="Close">
          <span aria-hidden="true">&times;</span>
        </button>
      </div>
      <div class="modal-body">
        <p>Modal body text goes here.</p>
      </div>
      <div class="modal-footer">
        <button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
        <button type="button" class="btn btn-primary">Save changes</button>
      </div>
    </div>
  </div>
</div>

BS3 の実装

<div class="modal fade" id="sampleModal" tabindex="-1">
  <div class="modal-backdrop fade in" style="height: 969px;"></div>
  <div class="modal-dialog">
    <div class="modal-content">
      <div class="modal-header">
        <button type="button" class="close" data-dismiss="modal"><span>×</span></button>
        <h5 class="modal-title">Modal title</h5>
      </div>
      <div class="modal-body">
        <p>Modal body text goes here.</p>
      </div>
      <div class="modal-footer">
        <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
        <button type="button" class="btn btn-primary">Save changes</button>
      </div>
    </div>
  </div>
</div>
◆ BS3
.modal-open .modal {
    overflow-x: hidden;
    overflow-y: auto;
}
 
.fade.in {
    opacity: 1;
}
 
.modal-backdrop.in {
    filter: alpha(opacity=50);
    opacity: .5;
}
 
.modal-backdrop.fade {
    filter: alpha(opacity=0);
    opacity: 0;
}
 
.modal {
    position: fixed;
    top: 0;
    right: 0;
    bottom: 0;
    left: 0;
    z-index: 1040;
    display: none;
    overflow: hidden;
    -webkit-overflow-scrolling: touch;
    outline: 0;
}
 
.modal-backdrop {
    position: absolute;
    top: 0;
    right: 0;
    left: 0;
    background-color: #000;
}
 
.fade {
    opacity: 0;
    -webkit-transition: opacity .15s linear;
    -o-transition: opacity .15s linear;
    transition: opacity .15s linear;
}

手動でモーダルを表示するには、いろいろとやることがある

https://coliss.com/articles/build-websites/operation/javascript/prevent-page-scrolling-when-a-modal-is-open.html