コンテンツへスキップ

createTemplatePromise

カテゴリー
エクスポートサイズ
497 B
最終更新日
先週

Promiseとしてのテンプレート。カスタムダイアログ、モーダル、トーストなどの構築に役立ちます。

警告

この関数は 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として呼び出す
  • テンプレート - 新しいDSLではなく、Vueテンプレートを使用してレンダリング
  • TypeScript - ジェネリック型による完全な型安全性
  • レンダリングレス - UIを完全に制御
  • トランジション - Vueトランジションをサポート

この関数は、vue-template-promise から移行されました

使い方

createTemplatePromise は、<script setup> でテンプレート内で直接使用できるVueコンポーネントを返します。

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()

テンプレート内で 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 }),
})

これは、UIテンプレートを表現するために、スクリプトで新しい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.dokyumento.jp/createTemplatePromise
 */
export declare function createTemplatePromise<Return, Args extends any[] = []>(
  options?: TemplatePromiseOptions,
): TemplatePromise<Return, Args>

ソース

ソースデモドキュメント

貢献者

Anthony Fu
Anthony Fu
Aaron-zon
Haoqun Jiang
Bruce

変更履歴

v12.0.0-beta.1 2024/11/21
0a9ed - feat!: Vue 2 のサポートを削除し、バンドルを最適化してクリーンアップしました (#4349)
v10.8.0 2024/02/20
a086e - fix: より厳密な型
v10.1.1 2023/5/1
fc8cf - 修正: 一時的にvue 3.3の型エラーを回避 (#3042)
v10.0.0-beta.5 2023/4/13
13169 - 機能: 新しい関数を追加 (#2957)

MITライセンスの下で公開されています。