createTemplatePromise
將模板作為 Promise。適用於建構自訂對話框、模態視窗、Toast 等。
警告
此函數僅適用於 Vue 3
範例
用法
vue
<script setup lang="ts">
import { createTemplatePromise } from '@vueuse/core'
const TemplatePromise = createTemplatePromise<ReturnType>()
async function open() {
const result = await TemplatePromise.start()
// button is clicked, result is 'ok'
}
</script>
<template>
<TemplatePromise v-slot="{ promise, resolve, reject, args }">
<!-- your UI -->
<button @click="resolve('ok')">
OK
</button>
</TemplatePromise>
</template>
特性
- 程式化 - 將您的 UI 作為 promise 調用
- 模板 - 使用 Vue 模板來渲染,而不是新的 DSL
- TypeScript - 透過泛型類型實現完整的類型安全
- 無渲染 - 您完全掌控 UI
- 轉場效果 - 支援 Vue 轉場效果
此函數從 vue-template-promise 遷移而來
用法
createTemplatePromise
返回一個 Vue 元件,您可以直接在帶有 <script setup>
的模板中使用它
ts
import { createTemplatePromise } from '@vueuse/core'
const TemplatePromise = createTemplatePromise()
const MyPromise = createTemplatePromise<boolean>() // with generic type
js
import { createTemplatePromise } from '@vueuse/core'
const TemplatePromise = createTemplatePromise()
const MyPromise = createTemplatePromise() // with generic type
在模板中,使用 v-slot
來存取 promise 和 resolve 函數。
vue
<template>
<TemplatePromise v-slot="{ promise, resolve, reject, args }">
<!-- you can have anything -->
<button @click="resolve('ok')">
OK
</button>
</TemplatePromise>
<MyPromise v-slot="{ promise, resolve, reject, args }">
<!-- another one -->
</MyPromise>
</template>
插槽最初不會被渲染(類似於 v-if="false"
),直到您從元件調用 start
方法。
ts
const result = await TemplatePromise.start()
一旦在模板中調用 resolve
或 reject
,promise 將被解析或拒絕,並返回您傳入的值。一旦解析,插槽將自動移除。
傳遞參數
您可以將參數傳遞給帶有參數的 start
。
ts
import { createTemplatePromise } from '@vueuse/core'
const TemplatePromise = createTemplatePromise<boolean, [string, number]>()
js
import { createTemplatePromise } from '@vueuse/core'
const TemplatePromise = createTemplatePromise()
ts
const result = await TemplatePromise.start('hello', 123) // Pr
在模板插槽中,您可以透過 args
屬性存取參數。
vue
<template>
<TemplatePromise v-slot="{ args, resolve }">
<div>{{ args[0] }}</div>
<!-- hello -->
<div>{{ args[1] }}</div>
<!-- 123 -->
<button @click="resolve(true)">
OK
</button>
</TemplatePromise>
</template>
轉場效果
您可以使用轉場效果來為插槽添加動畫。
vue
<script setup lang="ts">
const TemplatePromise = createTemplatePromise<ReturnType>({
transition: {
name: 'fade',
appear: true,
},
})
</script>
<template>
<TemplatePromise v-slot="{ resolve }">
<!-- your UI -->
<button @click="resolve('ok')">
OK
</button>
</TemplatePromise>
</template>
<style scoped>
.fade-enter-active,
.fade-leave-active {
transition: opacity 0.5s;
}
.fade-enter,
.fade-leave-to {
opacity: 0;
}
</style>
了解更多關於 Vue 轉場效果。
動機
以程式化的方式調用對話框或模態視窗的常見方法如下
ts
const dialog = useDialog()
const result = await dialog.open({
title: 'Hello',
content: 'World',
})
這會透過將這些資訊發送到頂層元件並讓它渲染對話框來運作。然而,這限制了您可以在 UI 中表達的靈活性。例如,您可能希望標題是紅色的,或者有額外的按鈕等等。您最終會得到很多像這樣的選項
ts
const result = await dialog.open({
title: 'Hello',
titleClass: 'text-red',
content: 'World',
contentClass: 'text-blue text-sm',
buttons: [
{ text: 'OK', class: 'bg-red', onClick: () => {} },
{ text: 'Cancel', class: 'bg-blue', onClick: () => {} },
],
// ...
})
即使這樣也不夠靈活。如果您想要更多,您最終可能會使用手動渲染函數。
ts
const result = await dialog.open({
title: 'Hello',
contentSlot: () => h(MyComponent, { content }),
})
這就像在腳本中重新發明一種新的 DSL 來表達 UI 模板。
因此,此函數允許在模板中表達 UI 而不是在腳本中,這才是它應該在的地方,同時仍然能夠以程式化的方式進行操作。
類型宣告
顯示類型宣告
typescript
export interface TemplatePromiseProps<Return, Args extends any[] = []> {
/**
* The promise instance.
*/
promise: Promise<Return> | undefined
/**
* Resolve the promise.
*/
resolve: (v: Return | Promise<Return>) => void
/**
* Reject the promise.
*/
reject: (v: any) => void
/**
* Arguments passed to TemplatePromise.start()
*/
args: Args
/**
* Indicates if the promise is resolving.
* When passing another promise to `resolve`, this will be set to `true` until the promise is resolved.
*/
isResolving: boolean
/**
* Options passed to createTemplatePromise()
*/
options: TemplatePromiseOptions
/**
* Unique key for list rendering.
*/
key: number
}
export interface TemplatePromiseOptions {
/**
* Determines if the promise can be called only once at a time.
*
* @default false
*/
singleton?: boolean
/**
* Transition props for the promise.
*/
transition?: TransitionGroupProps
}
export type TemplatePromise<
Return,
Args extends any[] = [],
> = DefineComponent<object> & {
new (): {
$slots: {
default: (_: TemplatePromiseProps<Return, Args>) => any
}
}
} & {
start: (...args: Args) => Promise<Return>
}
/**
* Creates a template promise component.
*
* @see https://vueuse.dev.org.tw/createTemplatePromise
*/
export declare function createTemplatePromise<Return, Args extends any[] = []>(
options?: TemplatePromiseOptions,
): TemplatePromise<Return, Args>