跳到主要内容

createTemplatePromise

分类
导出大小
390 B
上次更改
上个月

将模板作为 Promise。可用于构建自定义对话框、模态框、提示信息等。

演示

用法

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>

特性

  • 编程化 - 以 promise 形式调用你的 UI
  • 模板 - 使用 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>

在组件调用 start 方法之前,插槽不会被渲染(类似于 v-if="false")。

ts
const 
result
= await
TemplatePromise
.
start
()

一旦在模板中调用 resolvereject,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,这才是它应有的位置,同时仍然能够以编程方式进行操作。

类型声明

显示类型声明
ts
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.org.cn/createTemplatePromise * * @__NO_SIDE_EFFECTS__ */ export declare function
createTemplatePromise
<
Return
,
Args
extends any[] = []>(
options
?: TemplatePromiseOptions,
):
TemplatePromise
<
Return
,
Args
>

来源

源代码演示文档

贡献者

Anthony Fu
Anthony Fu
SerKo
Scott Bedard
Arthur Darkstone
Robin
David Gonzalez
ethmcc
Aaron-zon
Haoqun Jiang
Bruce

更新日志

5fd3a - 修复:更新 createReusableTemplate 和 createTemplateP... 的返回类型 (#4962)
v13.6.0
d32f8 - refactor: 为所有纯函数添加 @__NO_SIDE_EFFECTS__ 注释 (#4907)
0a9ed - feat!: 放弃对 Vue 2 的支持,优化打包并清理 (#4349)
v10.8.0
a086e - fix: 更严格的类型
v10.1.1
fc8cf - 修复:暂时解决 vue 3.3 中的类型错误 (#3042)

根据 MIT 许可证发布。