Vue3 Teleport の魅力：初心者エンジニアが体験した話

## はじめに
こんにちは。入社2年目、実務経験約半年の駆け出しフロントエンドエンジニアです。日々の業務では主にNuxt、Vue、AWS、TypeScriptを使って開発を行っています。

今回は、Vue3.5の情報を見ていた際に、「Teleport」のついて初めて知り、こんな便利なものがあったのかと驚いたので記事にしようと思いました。
「Teleport」については前からある機能なのですが、私を含めて、Vue初心者エンジニアの方にぜひ知ってもらえたらと思って書きます。

## 1. Teleport とは
Teleportは、Vue3 で導入された新しい組み込みコンポーネントです。
簡単にいうと、Teleportで囲んだコンポーネントを、指定したDOMノードにテレポートすることができるという認識をしています。

公式ドキュメントでは、次のように説明されています：
https://ja.vuejs.org/guide/built-ins/teleport
> テレポートを使用すると、コンポーネントのテンプレートの一部を、コンポーネントのDOM階層の外側にあるDOMノードに「テレポート」できます。

## 2. Teleportの基本的な使い方
Teleportの基本的な使い方は以下の通りです：

```vuejs
<teleport to="selector">
<!-- コンテンツ -->
</teleport>
```
- `to`プロパティには、テレポート先の要素を指定するCSSセレクタを指定します。
- テレポートされるコンテンツは、`<teleport>`タグの中に記述します。

## 3. 実際の開発での使用例：SPハンバーガーメニュー
私が実際活用できたのは、スマートフォン（SP）用のハンバーガーメニューの実装でした。
具体的には以下のような要件がありました：
- メニューを`position:fixed`で表示する
- 左から右へスライドインするアニメーションを付ける
- メニューが他の要素に覆われないようにする

従来の方法では、CSSのz-indexの調整や、親要素のスタイリングの影響で思うような表示ができず、メニューが崩れてしまうことがありました。

```vuejs
<script setup lang='ts'>
import { ref } from 'vue'
const isMenuOpen = ref<boolean>(false)
</script>

<template>
    <div>
        <button @click="isMenuOpen = true">メニューを開く</button>
        <!-- ハンバーガーメニューの内容 -->
        <teleport to="body">
            <div v-if="isMenuOpen" class="menu-overlay">
                <div class="menu-content">
                    <button @click="isMenuOpen = false">閉じる</button>
                    <nav>
                        <ul>
                            <li><a href="#">ホーム</a></li>
                            <li><a href="#">about</a></li>
                            <li><a href="#">サービス</a></li>
                            <li><a href="#">お問い合わせ</a></li>
                        </ul>
                    </nav>
                </div>
            </div>
        </teleport>
    </div>
</template>

<style scoped>
.menu-overlay {
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background-color: rgba(0, 0, 0, 0.5);
    z-index: 999;
}

.menu-content {
    position: fixed;
    top: 0;
    left: 0;
    width: 80%;
    height: 100%;
    background-color: #fff;
    transform: translateX(-100%);
    transition: transform 0.3s ease-in-out;
}

.menu-overlay .menu-content {
    transform: translateX(0);
}
</style>

```

この実装のポイントは以下の通りです：

1. Teleportを使用して、メニューの内容を`<body>`直下に配置
2. オーバーレイ(`.menu-overlay`)とメニュー本体(`.menu-content`)を分けて実装
3. cssアニメーションを使用して、左からスライドイン効果を実現

## 4. Teleportの利点
1. z-indexの問題が解消される：
 　`<body>`直下に配置されるため、他の要素に覆われる心配がありません。
  
1. 親要素のスタイリングの影響を受けない：
　メニューが独立したいちに配置されるため、親要素のスタイルには影響されません。
 
1. コードの見通しがよくなる：
　メニューの論理的な位置を保ちつつ、物理的な配置を制御できます。

 この方法を使用することで、以前は苦労していたSPハンバーガーメニューやモーダルなどの実装が格段に簡単になり、予期せぬスタイルの崩れも防ぐことができました。


## 5. 注意点
Teleportを使用する際の注意点：
1. toプロパティの指定
    - `to`プロパティには、有効なCSSセレクタまたはDOM要素を指定する必要があります。
    - 指定した要素が存在しない場合、Teleportは機能しません。
    - 動的な`to`の値を使用する場合、要素が存在することを確認してからTeleportを使用するようにしましょう。 
2. SSR（サーバーサイドレンダリング）との互換性
    - Teleportはクライアントサイドでのみ完全に機能します。
    - SSRを使用する場合、サーバー上でのレンダリング結果とクライアントでの最終的なDOMの構造が異なる可能性があります。
    - これにより、ハイドレーション（hydration）の警告が発生する場合があります。


## 6. まとめ
`Teleport`はVue3で使える機能で、コンポーネントの一部をDOMツリーの別の場所に移動できます。
主な特徴は：
1. モーダルやポップアップなどの実装が簡単になります。
1. コードの構造はそのままで、画面上の配置だけ変えられます。
1. z-indexの問題を解決しやすくなります。

使い方は簡単ですが、SSRの時は注意が必要です。

私自身、ハンバーガーメニューの実装で苦労しましたが、テレポートで簡単に解決できました。
まだ使ったことのない方は、ぜひ試してみてください。
きっと新しい可能性が広がります！（私含め初学者の方）