PortalVueはvue.jsに記述した要素(HTML)を記述したその場所に表示させるのではなく事前に指定した別の場所に表示させることができるプラグインです。

PHPのフレームワークで有名なLaravel8でもモーダルにPortalVueを利用しているほど便利なプラグインでVue 3ではTeleportという機能で同様の処理を行うことができます。teleportはある場所から別の場所に瞬間に移動する意味を持つ単語で単語から機能のイメージを持つことができます。

Laravel8のvue.jsはバージョン2です。PortalVueは、2020年10月現在はVue3には対応しておらずVue2で利用可能です。開発者の人が腕を骨折しているため遅れがでているようです。
fukidashi

PortalVueがどのようなものか基本機能の確認を行います。PortalVueを利用したモーダルウィンドウについては別記事で公開しています。

動作確認

言葉よりも動作確認を行うことですぐにどのようなものか理解することができるので動作確認を行ってみましょう。cdnを使って手元のPCですぐに確認できます。

上がvueのcdnで下がPortalVueのcdnです。


<script src="http://unpkg.com/vue/dist/vue.js"></script>
<script src="http://unpkg.com/portal-vue"></script>

基本的にはPortalVueを利用するためには2つのタグと2つの属性を設定するだけです。

portal-targetタグ 移動先の設定

移動先のタグにはportal-targetを利用します。portal-targetを識別するためにname属性を設定します。名前は任意でここではdestination(目的地)と設定しています。


<portal-target name="destination">
</portal-target>

portalタグ 移動元の設定

移動元のなるHTMLはportalタグで囲んでto属性にはportal-targetのname属性で設定した名前destinationを指定します。


<portal to="destination">
	<p>ここに記述した内容が別の場所で表示されます。</p>
</portal>

これで必要な設定は完了です。移動していることを確認するためにportalタグとportal-targetタグの間にh1タグを追加します。h1タグの下にportalの中で記述したpタグの内容が表示されれば正常に動作しています。


<!DOCTYPE html>
<html lang="ja">

<head>
	<meta charset="UTF-8">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<title>PortalVue</title>
</head>

<body>
	<div id="app">
		<portal to="destination">
			<p>ここに記述した内容が別の場所で表示されます。</p>
		</portal>
		<h1>PortaVueの動作確認</h1>
		<portal-target name="destination">
		</portal-target>
	</div>

	<script src="http://unpkg.com/vue/dist/vue.js"></script>
	<script src="http://unpkg.com/portal-vue"></script>
	<script>
		new Vue({
			el: '#app',
		})
	</script>
</body>

</html>

ブラウザで確認するとh1タグの下にportalタグの中身が表示されることが確認できます。

portalvueの動作確認
portalvueの動作確認

デベロッパーツールでの確認

デベロッパーツールを利用してHTMLにどのような変化が起きているのか確認してみましょう。

移動元にはv-portalクラスとスタイルのdisplay:none;が設定されたdivタグがあり、移動先にはvue-portal-targetクラスを持つdivタグの中に記述した内容が含まれていることがわかります。当たり前ですがh1タグの下に移動元の中身が移動していることをデベロッパーツールからも確認できます。

デベロッパーツールでの確認
デベロッパーツールでの確認

v-showとの組み合わせ

vue.jsのディレクティブのv-showと組み合わせて表示・非表示の切替を行うことができます。頻繁に切り替えを行うmodalを作成するときにもv-showを利用します。

v-ifを利用することもできます。
fukidashi

データプロパティのshow、Toggleボタン追加し、clickイベントを設定し、ボタンを押すとことで表示・非表示を切り替えるように設定を行います。


<body>
	<div id="app">
		<button @click="show = !show">Toggle</button>
		<portal to="destination">
			<p  v-show="show">ここに記述した内容が別の場所で表示されます。</p>
		</portal>
		<h1>PortaVueの動作確認</h1>
		<portal-target name="destination">
		</portal-target>
	</div>

	<script src="http://unpkg.com/vue/dist/vue.js"></script>
	<script src="http://unpkg.com/portal-vue"></script>
	<script>
		new Vue({
			el: '#app',
			data:{
				show:false,
			}
		})
	</script>
</body>

ボタンをクリックすることで表示・非表示と切り替わります。

ボタンをクリックする前の状態です。

portalとshowとの組み合わせ
portalとshowとの組み合わせ

Toggleボタンをクリックするとportalで設定した内容が表示されます。

portalで設定した内容が表示
portalで設定した内容が表示

Toggleボタンをクリックすると

transitionの追加

transitionと組み合わせて簡単なアニメーションを設定することができます。ボタンを押すとすぐに表示/非表示が即座に行われていましたがtransitionを設定することでゆっくりと表示/非表示されるようアニメーションを設定することができます。

transitionタグでv-showで表示・非表示を設定したpタグを囲みます。styleでクラスの追加も行う必要があります。下記のtransitionの設定では1sをかけてゆっくりと表示、非表示を行います。


<style>
.v-enter-active, .v-leave-active {
  transition: opacity 1s;
}
.v-enter, .v-leave-to{
  opacity: 0;
}
</style>
<body>
	<div id="app">
		<button @click="show = !show">Toggle</button>

		<portal to="destination">
			<transition>
			<p v-show="show">ここに記述した内容が別の場所で表示されます。</p>
			</transition>
		</portal>

		<h1>PortaVueの動作確認</h1>
		<portal-target name="destination">
		</portal-target>
	</div>

	<script src="http://unpkg.com/vue/dist/vue.js"></script>
	<script src="http://unpkg.com/portal-vue"></script>
	<script>
		new Vue({
			el: '#app',
			data:{
				show:false,
			}
		})
	</script>
</body>

PortalVueの有効・無効化

portalタグにpropsのdisabledを追加し、true, falseで有効、無効を設定することができます。プロパティを追加し、trueをfalseを切り替えることで有効・無効の切替も行うことができます。


<portal to="destination" :disabled="true">

disabledをtureに設定する(disabledを設定しない)と元の位置で表示されます。

複数のportalタグを設定した場合

portalタグを複数用意した場合にどのような動きになるか確認を行います。2つのportalを用意し同じ移動先のdestinationを設定します。2つの間にも一つpタグを入れておきます。特にpタグを入れる理由はありません。


<portal to="destination">
    <transition>
        <p v-show="show">こいつも別の場所で表示させたい</p>
    </transition>
</portal> -->
<portal to="destination">
    <p>ここに記述した内容が別の場所で表示されます。</p>
</portal>
<p>複数のportalを設定</p>
<portal to="destination">
    <p>これも一緒に表示させたい</p>
</portal>
<h1>PortaVueの動作確認</h1>
<portal-target name="destination">
</portal-target>

ブラウザで確認すると後に追加したportalタグの内容のみ表示されます。

複数のportalタグを設定
複数のportalタグを設定

複数のportalタグの中身を表示させたい場合はportal-targetタグにmultipleを追加します。


<portal-target name="destination" multiple >

確認すると複数のportalタグの内容が表示されるようになりました。

multiple設定後の動作確認
multiple設定後の動作確認

複数のportalの順番を設定

複数のportalタグを設定した場合に移動先で表示させる順番を変更することができます。

portalタグにpropsのorderを追加して、順番を入力してください。デフォルトでは0が入っています。


<portal to="destination" :order="2">
	<p>ここに記述した内容が別の場所で表示されます。</p>
</portal>
<p>複数のportalを設定</p>
<portal to="destination" :order="1">
	<p>これも一緒に表示させたい</p>
</portal>
<h1>PortaVueの動作確認</h1>
<portal-target name="destination" multiple >
</portal-target>

ブラウザで確認するとorderで入力した数字の順番に表示されていることがわかります。

表示順番を変更
表示順番を変更

ここまでの説明でPortalVueの基本機能の理解ができたので下記の文章でPortalVueを利用してモーダルウィンドウの作り方を確認していきます。