createReusableTemplate
createReusableTemplate
コンポーネントのスコープ内でテンプレートを定義し再利用します。
動機
テンプレートの一部を再利用する必要があることはよくあります。例えば:
<template>
<dialog v-if="showInDialog">
<!-- 複雑な内容 -->
</dialog>
<div v-else>
<!-- 複雑な内容 -->
</div>
</template>
コードをできるだけ再利用したいと考えます。通常、これらの重複した部分をコンポーネントに抽出する必要があります。しかし、別のコンポーネントにすると、ローカルバインディングにアクセスする能力を失います。それらのために props や emits を定義するのは時に面倒です。
この関数は、コンポーネントスコープ内でテンプレートを定義し再利用する方法を提供するために作られました。
使用法
前述の例を次のようにリファクタリングできます:
<script setup lang="ts">
import { createReusableTemplate } from '@vueuse/core'
const [DefineTemplate, ReuseTemplate] = createReusableTemplate()
</script>
<template>
<DefineTemplate>
<!-- 複雑な内容 -->
</DefineTemplate>
<dialog v-if="showInDialog">
<ReuseTemplate />
</dialog>
<div v-else>
<ReuseTemplate />
</div>
</template>
<DefineTemplate>はテンプレートを登録し、何もレンダリングしません。<ReuseTemplate>は<DefineTemplate>によって提供されたテンプレートをレンダリングします。<DefineTemplate>は<ReuseTemplate>より前に使用する必要があります。
注意: 可能な限り別のコンポーネントとして抽出することをお勧めします。この関数を乱用すると、コードベースに悪い習慣をもたらす可能性があります。
Options API
Options API と一緒に使用する場合、createReusableTemplate をコンポーネントのセットアップ外で定義し、テンプレートで使用するために components オプションに渡す必要があります。
<script>
import { createReusableTemplate } from '@vueuse/core'
import { defineComponent } from 'vue'
const [DefineTemplate, ReuseTemplate] = createReusableTemplate()
export default defineComponent({
components: {
DefineTemplate,
ReuseTemplate,
},
setup() {
// ...
},
})
</script>
<template>
<DefineTemplate v-slot="{ data, msg, anything }">
<div>{{ data }} passed from usage</div>
</DefineTemplate>
<ReuseTemplate :data="data" msg="The first usage" />
</template>
データの受け渡し
スロットを使用してテンプレートにデータを渡すこともできます:
<DefineTemplate>でv-slot="..."を使用してデータにアクセスします<ReuseTemplate>でデータを直接バインドしてテンプレートに渡します
<script setup lang="ts">
import { createReusableTemplate } from '@vueuse/core'
const [DefineTemplate, ReuseTemplate] = createReusableTemplate()
</script>
<template>
<DefineTemplate v-slot="{ data, msg, anything }">
<div>{{ data }} passed from usage</div>
</DefineTemplate>
<ReuseTemplate :data="data" msg="The first usage" />
<ReuseTemplate :data="anotherData" msg="The second usage" />
<ReuseTemplate v-bind="{ data: something, msg: 'The third' }" />
</template>
TypeScript サポート
createReusableTemplate はジェネリック型を受け入れ、テンプレートに渡されるデータに対する型サポートを提供します:
<script setup lang="ts">
import { createReusableTemplate } from '@vueuse/core'
// `DefineTemplate` と `ReuseTemplate` のペアを提供
const [DefineFoo, ReuseFoo] = createReusableTemplate<{ msg: string }>()
// 複数の再利用可能なテンプレートを作成可能
const [DefineBar, ReuseBar] = createReusableTemplate<{ items: string[] }>()
</script>
<template>
<DefineFoo v-slot="{ msg }">
{/* `msg` は `string` 型として扱われます */}
<div>Hello {{ msg.toUpperCase() }}</div>
</DefineFoo>
<ReuseFoo msg="World" />
{/* @ts-expect-error 型エラー! */}
<ReuseFoo :msg="1" />
</template>
配列の分割代入が好みでない場合、次の使用法も合法です:
<script setup lang="ts">
import { createReusableTemplate } from '@vueuse/core'
const { define: DefineFoo, reuse: ReuseFoo } = createReusableTemplate<{
msg: string
}>()
</script>
<template>
<DefineFoo v-slot="{ msg }">
<div>Hello {{ msg.toUpperCase() }}</div>
</DefineFoo>
<ReuseFoo msg="World" />
</template>
<script setup lang="ts">
import { createReusableTemplate } from '@vueuse/core'
const TemplateFoo = createReusableTemplate<{ msg: string }>()
</script>
<template>
<TemplateFoo.define v-slot="{ msg }">
<div>Hello {{ msg.toUpperCase() }}</div>
</TemplateFoo.define>
<TemplateFoo.reuse msg="World" />
</template>
::: warning
v-bind なしでのブール型のプロップスの受け渡しはサポートされていません。詳細は Caveats セクションを参照してください。
:::
プロップスと属性
デフォルトでは、<ReuseTemplate> に渡されたすべてのプロップスと属性はテンプレートに渡されます。特定のプロップスをDOMに渡したくない場合は、ランタイムプロップスを定義する必要があります:
import { createReusableTemplate } from '@vueuse/core'
const [DefineTemplate, ReuseTemplate] = createReusableTemplate({
props: {
msg: String,
enable: Boolean,
}
})
テンプレートにプロップスを渡したくない場合は、inheritAttrs オプションを渡すことができます:
import { createReusableTemplate } from '@vueuse/core'
const [DefineTemplate, ReuseTemplate] = createReusableTemplate({
inheritAttrs: false,
})
スロットの受け渡し
<ReuseTemplate> からスロットを戻すことも可能です。<DefineTemplate> で $slots からスロットにアクセスできます:
<script setup lang="ts">
import { createReusableTemplate } from '@vueuse/core'
const [DefineTemplate, ReuseTemplate] = createReusableTemplate()
</script>
<template>
<DefineTemplate v-slot="{ $slots, otherProp }">
<div some-layout>
<!-- スロットをレンダリングするために -->
<component :is="$slots.default" />
</div>
</DefineTemplate>
<ReuseTemplate>
<div>Some content</div>
</ReuseTemplate>
<ReuseTemplate>
<div>Another content</div>
</ReuseTemplate>
</template>
注意点
ブール型プロップス
Vue の動作とは異なり、boolean として定義されたプロップスが v-bind なしで渡された場合、または存在しない場合、それぞれ空の文字列または undefined に解決されます:
<script setup lang="ts">
import { createReusableTemplate } from '@vueuse/core'
const [DefineTemplate, ReuseTemplate] = createReusableTemplate<{
value?: boolean
}>()
</script>
<template>
<DefineTemplate v-slot="{ value }">
{{ typeof value }}: {{ value }}
</DefineTemplate>
<ReuseTemplate :value="true" />
<!-- boolean: true -->
<ReuseTemplate :value="false" />
<!-- boolean: false -->
<ReuseTemplate value />
<!-- string: -->
<ReuseTemplate />
<!-- undefined: -->
</template>
参考文献
この関数は vue-reuse-template から移行されました。
テンプレートの再利用に関する既存の Vue の議論/問題:
代替アプローチ:
※このページは Nuxt.js 公式ドキュメントの翻訳ページです。
公式ドキュメントの該当ページはこちら:
#