Vue でモーダルを作る:通常モーダルと Teleport モーダルの比較
Vue.js を使ったモーダルの実装には、DOMの構造内に配置する「通常モーダル」と、<body>直下に表示する「Teleportモーダル」の2通りのアプローチがあります。
それぞれの実装方法や特徴、使い分けのポイントを整理しながら、実際のコード例とともにご紹介します。
自分用メモとしてもまとめておきたい。
通常モーダルと Teleportモーダルとは?
「通常モーダル」は、そのままコンポーネントのDOMツリーの中にモーダルの要素を置く方法です。この方法はシンプルでわかりやすい反面、親要素のスタイルやレイアウトの影響を受けやすく、重ね順や位置がうまくいかないこともあります。経験上結構あれ?他の要素がバッティングしてるかも。となったりする。
一方、「Teleportモーダル」はVueのTeleportという機能を使って、モーダルの要素をDOMの<body>直下など指定した場所に移動して表示します。これにより親要素の影響を受けず、画面中央や最前面にモーダルを表示しやすくなります。
実装例
以下のコードでは、通常のモーダルと Teleport を用いたモーダルをそれぞれボタンで制御しています。
<template>
<section class="section">
<h1>モーダル</h1>
<div>
<button @click="toggleModal">モーダル開く</button>
<div v-if="isOpen" class="modal" @click.self="toggleModal">
<div class="modal__inner">
<p>普通のモーダル!</p>
<button @click="toggleModal">閉じる</button>
</div>
</div>
</div>
<div>
<button @click="toggleTeleportModal">Teleportモーダル開く</button>
<Teleport to="body">
<div v-if="isTeleportOpen" class="modal" @click.self="toggleTeleportModal">
<div class="modal__inner">
<p>Teleportで作ったモーダル!</p>
<button @click="toggleTeleportModal">閉じる</button>
</div>
</div>
</Teleport>
</div>
</section>
</template>
<script setup lang="ts">
import { ref } from 'vue';
const isOpen = ref(false);
const isTeleportOpen = ref(false);
const toggleModal = () => {
isOpen.value = !isOpen.value;
};
const toggleTeleportModal = () => {
isTeleportOpen.value = !isTeleportOpen.value;
};
</script>
<style lang="scss" scoped>
.modal {
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
background-color: rgba(0, 0, 0, 0.5);
display: flex;
justify-content: center;
align-items: center;
z-index: 9999;
&__inner {
background: #fff;
color: #222;
padding: 2rem;
border-radius: 1rem;
box-shadow: 0 0 20px rgba(0, 0, 0, 0.2);
max-width: 500px;
width: 90%;
position: relative;
}
}
</style>
.self 修飾子について
@click.self は、その要素自身がクリックされたときだけイベントを発火させる Vue の修飾子です。
モーダル背景(.modal)をクリックしたときにモーダルを閉じたいけど、モーダルの中身をクリックしたときには閉じたくない、という場合に便利です。
<div class="modal" @click.self="toggleModal">
<!-- モーダル内 -->
</div>
動作確認
まとめ
通常モーダルはシンプルに実装可能で、DOM構造との親和性が高いですね。
画像の上とかにモーダル出したい時は普通の方がいいと思う。
そのほかはTeleportモーダルで事足りてしまいそう。とっても楽でいいです。
おすすめの使い分け自分メモ
こんなときに使う!
親要素の影響を受けたくない Teleportモーダル
セクション内で使いたい 通常モーダル
Discussion