主题
createTemplatePromise
模板即承诺。可用于构建自定义对话框、模态窗口、提示等。
🌐 Template as Promise. Useful for constructing custom Dialogs, Modals, Toasts, etc.
示例
用法
🌐 Usage
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>特性
🌐 Features
- 编程式 - 将你的 UI 作为一个 Promise 调用
- 模板 - 使用 Vue 模板进行渲染,而不是新的 DSL
- TypeScript - 通过泛型类型实现完全类型安全
- 无渲染 - 你可以完全控制用户界面
- 过渡 - 使用 Vue 过渡支持
该函数已从 vue-template-promise 迁移
🌐 This function is migrated from vue-template-promise
用法
🌐 Usage
createTemplatePromise 返回一个 Vue 组件,你可以在模板中直接使用 <script setup>
ts
import { createTemplatePromise } from '@vueuse/core'
const TemplatePromise = createTemplatePromise()
const MyPromise = createTemplatePromise<boolean>() // with generic typejs
import { createTemplatePromise } from '@vueuse/core'
const TemplatePromise = createTemplatePromise()
const MyPromise = createTemplatePromise() // with generic type在模板中,使用 v-slot 来访问 promise 和 resolve 函数。
🌐 In template, use v-slot to access the promise and resolve functions.
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 方法。
🌐 The slot will not be rendered initially (similar to v-if="false"), until you call the start method from the component.
ts
const result = await TemplatePromise.start()一旦在模板中调用 resolve 或 reject,该承诺将被解决或拒绝,并返回你传入的值。一旦解决,插槽将自动被移除。
🌐 Once resolve or reject is called in the template, the promise will be resolved or rejected, returning the value you passed in. Once resolved, the slot will be removed automatically.
传递参数
🌐 Passing Arguments
你可以向 start 传递参数。
🌐 You can pass arguments to the start with arguments.
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 属性访问参数。
🌐 And in the template slot, you can access the arguments via args property.
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>单例模式
🌐 Singleton Mode
使用 singleton 选项可以确保同一时间只有一个承诺实例处于活动状态。如果在承诺已经处于活动状态时调用 start,它将返回现有的承诺,而不是创建一个新的。
🌐 Use the singleton option to ensure only one instance of the promise can be active at a time. If start is called while a promise is already active, it will return the existing promise instead of creating a new one.
ts
import { createTemplatePromise } from '@vueuse/core'
const TemplatePromise = createTemplatePromise<boolean>({
singleton: true,
})
// These will return the same promise if called in quick succession
const result1 = TemplatePromise.start()
const result2 = TemplatePromise.start() // returns the same promise as result1js
import { createTemplatePromise } from '@vueuse/core'
const TemplatePromise = createTemplatePromise({
singleton: true,
})
// These will return the same promise if called in quick succession
const result1 = TemplatePromise.start()
const result2 = TemplatePromise.start() // returns the same promise as result1转场
🌐 Transition
你可以使用转场来为插槽设置动画。
🌐 You can use transition to animate the slot.
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 Transition 的信息。
🌐 Learn more about Vue Transition.
插槽属性
🌐 Slot Props
该插槽提供以下属性:
🌐 The slot provides the following props:
| 属性 | 类型 | 描述 |
|---|---|---|
promise | Promise<Return> | undefined | 当前的 Promise 实例 |
resolve | (v: Return | Promise<Return>) => void | 用一个值来解决该 Promise |
reject | (v: any) => void | 拒绝该 Promise |
args | Args | 传递给 start() 的参数 |
isResolving | boolean | 在解决传递给 resolve 的另一个 Promise 时的 true |
key | number | 列表渲染的唯一键 |
vue
<template>
<TemplatePromise v-slot="{ promise, resolve, reject, args, isResolving }">
<div v-if="isResolving">
Loading...
</div>
<div v-else>
<button @click="resolve('ok')">
OK
</button>
<button @click="reject('cancelled')">
Cancel
</button>
</div>
</TemplatePromise>
</template>动机
🌐 Motivation
以编程方式调用对话框或模态框的常见方法如下:
🌐 The common approach to call a dialog or a modal programmatically would be like this:
ts
const dialog = useDialog()
const result = await dialog.open({
title: 'Hello',
content: 'World',
})这可以通过将这些信息发送到顶层组件并让其渲染对话框来实现。然而,这限制了你在用户界面中表达灵活性的能力。例如,你可能希望标题是红色的,或者有额外的按钮等。最终你会得到很多选项,例如:
🌐 This would work by sending these information to the top-level component and let it render the dialog. However, it limits the flexibility you could express in the UI. For example, you could want the title to be red, or have extra buttons, etc. You would end up with a lot of options like:
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: () => {} },
],
// ...
})即使这样也不够灵活。如果你想要更多,你可能最终需要手动渲染函数。
🌐 Even this is not flexible enough. If you want more, you might end up with manual render function.
ts
const result = await dialog.open({
title: 'Hello',
contentSlot: () => h(MyComponent, { content }),
})这就像在脚本中重新发明一种新的 DSL 来表达 UI 模板。
🌐 This is like reinventing a new DSL in the script to express the UI template.
所以这个函数允许在模板中而不是脚本中表达用户界面,这是它本应存在的地方,同时仍然可以通过程序进行操作。
🌐 So this function allows expressing the UI in templates instead of scripts, where it is supposed to be, while still being able to be manipulated programmatically.