Portal-vueを使用してVue.jsアプリの外部でDOMを制御する
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>
これで、AComponentとOtherComponentの両方がレンダリングされている限り、AComponentのportalのコンテンツはでレンダリングされます。 ]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>
これで、AComponentとOtherComponentの両方がレンダリングされている限り、AComponentのportalのコンテンツはでレンダリングされます。 ]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を使用しないことをお勧めします。