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を使用しないことをお勧めします。