Vue.jsの最大の強みの1つは、古いアプリや静的ページの一部を拡張または置換するために使用できることです。 この進歩的な性質により、Vueを段階的に採用したり、既存のアプリを改善するために使用したりすることができます。 portal-vue by Linus Borg は、VueコンポーネントをDOM内のどこにでも、親コンポーネントの外に、またはVueアプリ全体にレンダリングできるようにすることで、この柔軟性を拡張します。

インストール

経由でportal-vueをインストールします。 ヤーンまたはNPM。

# Yarn
$ yarn add portal-vue
# NPM
$ npm install portal-vue --save

次に、PortalVueプラグインを有効にします。

main.js
import Vue from 'vue';
import PortalVue from 'portal-vue';
import App from 'App.vue';

Vue.use(PortalVue);

new Vue({
  el: '#app',
  render: h => h(App)
});

ターゲティングコンポーネント

それでは、元のportalを作成するソースコンポーネントを作成しましょう。 独自のコンテンツを持つこともでき、portalコンポーネント内のものだけが移動されます。

AComponent.vue
<template>
  <div>
    <portal to="other-component">
      <p>{{message}}</p>
    </portal>
    <p>Other stuff stays here.</p>
  </div>
</template>

<script>

export default {
  data() {
    return {
      message: 'I get rendered in OtherComponent!'
    }
  }
}

</script>

これで、AComponentOtherComponentの両方がレンダリングされている限り、AComponentportalのコンテンツはでレンダリングされます。 ]OtherComponent。 1つのコンポーネントに複数のポータルを配置して、さまざまな場所に移動することもできます。

AComponent.vue
<template>
  <div>
    <portal-target name="other-component">
    </portal-target>
    <p>I have my own stuff too!</p>
  </div>
</template>

DOMのどこをターゲットにする

小さな変更で、ポータルコンテンツをWebページ全体のDOMのどこにでも出力できるようになりました。

AComponent.vue
<template>
  <div>
    <portal target-el="#place-on-the-page">
      <p>{{message}}</p>
    </portal>
    <p>Other stuff stays here.</p>
  </div>
</template>

<script>

export default {
  data() {
    return {
      message: 'I get rendered in the element with the id #place-on-the-page!'
    }
  }
}

</script>

これで、AComponentOtherComponentの両方がレンダリングされている限り、AComponentportalのコンテンツはでレンダリングされます。 ]OtherComponent。 1つのコンポーネントに複数のポータルを配置して、さまざまな場所に移動することもできます。

index.html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>Vue-Portal Example</title>
  </head>
  <body>
    <!-- Vue app -->
    <div id="app">
      ...
    </div>
    <script src="/dist/build.js"></script>

    <!-- Other random stuff on the page -->
    <section class="something-else">
      <h4>What is going on here! Who let the Vue app out?</h4>

      <!-- Contents of the portal replace the div here -->
      <div id="place-on-the-page">
      </div>
    </section>
  </body>
</html>

きちんとね?

オプション

  • disable プロップを使用して、コンテンツがポータルを「通過」するかどうかを切り替えることができます。 falseに設定すると、portal-targetまたはtarget-elではなく、portalコンポーネント内のコンテンツがレンダリングされます。 この小道具は反応性があるので、自由に変更できます。
  • ポータルが無効になっている場合は、 Slim プロップを追加して、余分なラッパー要素を追加しないようにすることもできます。
  • tag プロップを使用して、disableの場合のようにportalコンポーネントがレンダリングする要素を決定することもできます。

潜在的な問題

ここで詳細な説明を参照してください。

  • PortalおよびPortalTargetコンポーネントは抽象コンポーネントであるため、奇妙な動作をする可能性があるため、通常のコンポーネントのように操作したりアクセスしたりしないでください。
  • SSRを使用する場合、 portal-target コンポーネントは、DOMのportalコンポーネントの後に表示される必要があります。 そうしないと、Vueが混乱し、アプリ全体が再レンダリングされます。
  • また、SSRを使用する場合は、DOMの外部にあるターゲット要素が実際のHTML要素ではないことを確認する必要があります。 使用する習慣 (偽物でさえ)
  • ポータル化されたコンテンツのrefsは現在非同期であり、コンポーネントの最初または2番目のティックでは使用できません。 setTimeout を使用して少し待つか、this.nextTickを2回呼び出す必要があります。 ポータルのコンテンツでrefsを使用しないことをお勧めします。