Vue3のテレポートを使ってモーダルを作った時に、ん?となったとこ
職場でNuxt3を使っていて、モーダル画面を作ることになりました。
で、普通にモーダルを作る時と同じ感覚で作ってたら、ファイルの切り出し方で混乱したので整理しときます。
まず、テレポートとは?
頑張って公式の文章から理解しようとしましたが無理でした。。。
サンプルコード見たり、色々調べる中で以下の説明が一番簡潔でわかりやすく感じました。
定義したコンポーネントが属するDOMツリーとは別の場所に、まるでテレポートしたかのようにコンポーネントを移動できる機能です。
その後このビデオを見ながら一緒にサンプルを作ると、とりあえず機能の理解はしっかりできるかと。
モーダルを作ろう
まず、普通に1つのファイルでモーダル表示ができるページを作ろうとするとこんな感じになるかと思います。
<!-- app/pages/main.vue --> <template> <div> <button @click="showFlg = !showFlg">モーダル開閉</button> <!-- メインページのコンテンツ 省略 --> : <!-- モーダル --> <div :v-show="showFlg"> <!-- 中身省略 --> : </div> </div> </template> <script> export default{ data(){ return { showFlg: false, } } } </script>
じゃあこのモーダル部分を別ファイルに切り出そうとしたとき、どう分けるでしょうか??
Nuxt2・Vue2までのモーダル
- メインページ:モーダル開閉のフックになる要素を配置
- モーダルコンポーネント:モーダル画面
他の言語でもこういう感じで分けるかと思います。
<!-- app/pages/main.vue --> <template> <div> <button @click="showFlg = !showFlg">モーダル開く</button> <!-- メインページのコンテンツ 省略 --> : <!-- モーダル --> <Modal :v-show="showFlg" /> </div> </template> <script> export default{ data(){ return { showFlg: false, } } } </script>
<!-- app/components/Modal.vue --> <template> <div> <!-- 中身省略 --> : </div> </template>
テレポート使ってモーダルを作ってみる
- メインページ:モーダルを表示させるためのテレポート先を用意
- モーダルコンポーネント:モーダル開閉のフックになる要素+モーダル画面
ほぉ。テレポートは記載箇所にとらわれず、指定した場所にまるっとごっそり移動できる機能でした。
つまり記載と表示を意図的にずらせるため、モーダル関連を一括りのファイルにしても、 テレポート先の記載位置が合っていれば、正しく表示できるってわけなのでした。
<!-- app/pages/main.vue --> <template> <div> <Modal /> <!-- メインページのコンテンツ 省略 --> : <!-- テレポート先を用意してあげる --> <div id="modal-display"></div> </div> </template>
<!-- app/components/Modal.vue --> <template> <div> <button @click="showFlg = !showFlg">モーダル開く</button> <teleport to="#modal-display"> <div :v-show="showFlg"> <!-- 中身省略 --> : </div> </teleport> </div> </template> <script> export default{ data(){ return { showFlg: false, } } } </script>
所感
DOM要素を機能ごとにまとめられるのが新鮮。
今までvueやnuxtでモーダルを作ろうとするとパッケージを入れるか、頑張って自作するしか無かったが、サクッとできるようになったのは良い。
でも記載と表示がずれるので、慣れるまで引っかかりそう。
今まで表示部分に手を入れる場合、ブラウザの開発者ツールを頼りにしていたが、テレポートを使ってそうだったらコードベースで読んだ方がいいのかなと思う。
モーダル以外でテレポートの使い所が思いつかないので、一旦Vue3、Nuxt3以降、モーダル作るときはテレポートに注意!と覚えておこう。