createReusableTemplate
在組件作用域內定義和重用模板。
動機
通常會有重用模板某些部分的需求。例如
<template>
<dialog v-if="showInDialog">
<!-- something complex -->
</dialog>
<div v-else>
<!-- something complex -->
</div>
</template>
我們希望盡可能地重用我們的程式碼。因此,通常我們可能需要將這些重複的部分提取到一個組件中。然而,在一個分離的組件中,您會失去訪問本地綁定的能力。為它們定義 props 和 emits 有時可能會很繁瑣。
因此,這個函數旨在提供一種在組件作用域內定義和重用模板的方法。
用法
在前面的例子中,我們可以將其重構為
<script setup>
import { createReusableTemplate } from '@vueuse/core'
const [DefineTemplate, ReuseTemplate] = createReusableTemplate()
</script>
<template>
<DefineTemplate>
<!-- something complex -->
</DefineTemplate>
<dialog v-if="showInDialog">
<ReuseTemplate />
</dialog>
<div v-else>
<ReuseTemplate />
</div>
</template>
<DefineTemplate>
將註冊模板且不渲染任何內容。<ReuseTemplate>
將渲染由<DefineTemplate>
提供的模板。<DefineTemplate>
必須在<ReuseTemplate>
之前使用。
注意:建議盡可能提取為單獨的組件。濫用此函數可能會導致您的程式碼庫出現不良實務。
Options API
當與 Options API 一起使用時,您需要將 createReusableTemplate
定義在組件 setup 之外,並傳遞到 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>
傳遞資料
您也可以使用插槽將資料傳遞到模板
- 使用
v-slot="..."
來訪問<DefineTemplate>
上的資料 - 直接在
<ReuseTemplate>
上綁定資料以將其傳遞到模板
<script setup>
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'
// Comes with pair of `DefineTemplate` and `ReuseTemplate`
const [DefineFoo, ReuseFoo] = createReusableTemplate<{ msg: string }>()
// You can create multiple reusable templates
const [DefineBar, ReuseBar] = createReusableTemplate<{ items: string[] }>()
</script>
<template>
<DefineFoo v-slot="{ msg }">
<!-- `msg` is typed as `string` -->
<div>Hello {{ msg.toUpperCase() }}</div>
</DefineFoo>
<ReuseFoo msg="World" />
<!-- @ts-expect-error Type 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>
警告
不支援在沒有 v-bind
的情況下傳遞布林值 props。有關更多詳細資訊,請參閱 注意事項 部分。
Props 和 Attributes
預設情況下,所有傳遞到 <ReuseTemplate>
的 props 和 attributes 都將傳遞到模板。如果您不希望某些 props 傳遞到 DOM,則需要定義 runtime props
import { createReusableTemplate } from '@vueuse/core'
const [DefineTemplate, ReuseTemplate] = createReusableTemplate({
props: {
msg: String,
enable: Boolean,
}
})
如果您不想將任何 props 傳遞到模板,則可以傳遞 inheritAttrs
選項
import { createReusableTemplate } from '@vueuse/core'
const [DefineTemplate, ReuseTemplate] = createReusableTemplate({
inheritAttrs: false,
})
傳遞插槽
也可以從 <ReuseTemplate>
傳遞插槽回來。您可以從 $slots
訪問 <DefineTemplate>
上的插槽
<script setup>
import { createReusableTemplate } from '@vueuse/core'
const [DefineTemplate, ReuseTemplate] = createReusableTemplate()
</script>
<template>
<DefineTemplate v-slot="{ $slots, otherProp }">
<div some-layout>
<!-- To render the slot -->
<component :is="$slots.default" />
</div>
</DefineTemplate>
<ReuseTemplate>
<div>Some content</div>
</ReuseTemplate>
<ReuseTemplate>
<div>Another content</div>
</ReuseTemplate>
</template>
注意事項
布林值 props
與 Vue 的行為相反,定義為 boolean
且在沒有 v-bind
或缺席的情況下傳遞的 props 將分別解析為空字串或 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 討論/問題
替代方法
型別宣告
顯示型別宣告
type ObjectLiteralWithPotentialObjectLiterals = Record<
string,
Record<string, any> | undefined
>
type GenerateSlotsFromSlotMap<
T extends ObjectLiteralWithPotentialObjectLiterals,
> = {
[K in keyof T]: Slot<T[K]>
}
export type DefineTemplateComponent<
Bindings extends Record<string, any>,
MapSlotNameToSlotProps extends ObjectLiteralWithPotentialObjectLiterals,
> = DefineComponent & {
new (): {
$slots: {
default: (
_: Bindings & {
$slots: GenerateSlotsFromSlotMap<MapSlotNameToSlotProps>
},
) => any
}
}
}
export type ReuseTemplateComponent<
Bindings extends Record<string, any>,
MapSlotNameToSlotProps extends ObjectLiteralWithPotentialObjectLiterals,
> = DefineComponent<Bindings> & {
new (): {
$slots: GenerateSlotsFromSlotMap<MapSlotNameToSlotProps>
}
}
export type ReusableTemplatePair<
Bindings extends Record<string, any>,
MapSlotNameToSlotProps extends ObjectLiteralWithPotentialObjectLiterals,
> = [
DefineTemplateComponent<Bindings, MapSlotNameToSlotProps>,
ReuseTemplateComponent<Bindings, MapSlotNameToSlotProps>,
] & {
define: DefineTemplateComponent<Bindings, MapSlotNameToSlotProps>
reuse: ReuseTemplateComponent<Bindings, MapSlotNameToSlotProps>
}
export interface CreateReusableTemplateOptions<
Props extends Record<string, any>,
> {
/**
* Inherit attrs from reuse component.
*
* @default true
*/
inheritAttrs?: boolean
/**
* Props definition for reuse component.
*/
props?: ComponentObjectPropsOptions<Props>
}
/**
* This function creates `define` and `reuse` components in pair,
* It also allow to pass a generic to bind with type.
*
* @see https://vueuse.dev.org.tw/createReusableTemplate
*/
export declare function createReusableTemplate<
Bindings extends Record<string, any>,
MapSlotNameToSlotProps extends
ObjectLiteralWithPotentialObjectLiterals = Record<"default", undefined>,
>(
options?: CreateReusableTemplateOptions<Bindings>,
): ReusableTemplatePair<Bindings, MapSlotNameToSlotProps>
原始碼
貢獻者
更新日誌
v12.6.0
on 2/14/2025v12.0.0-beta.1
on 11/21/2024v10.8.0
on 2/20/2024a086e
- fix: 更嚴格的型別v10.3.0
on 7/30/2023v10.1.1
on 5/1/2023b3323
- fix: 改善 hmr 支援v10.0.0-beta.5
on 4/13/2023