Popconfirm 气泡确认框

贴着触发器浮出的确认气泡。

写得真好,期待下一章。

这段剧情和原作不一样吧?

已收藏。

<script setup lang="ts">
  import { ref } from 'vue'
  import { Button, Inline, Popconfirm, Stack, Text } from '@hina-ui/vue'

  const comments = ref(['写得真好,期待下一章。', '这段剧情和原作不一样吧?', '已收藏。'])

  function remove(index: number) {
    comments.value.splice(index, 1)
  }
</script>

<template>
  <Stack gap="sm" align="stretch" class="w-96">
    <Inline
      v-for="(comment, index) in comments"
      :key="comment"
      align="center"
      justify="between"
      gap="sm"
    >
      <Text size="sm">{{ comment }}</Text>
      <Popconfirm
        title="删除这条评论?"
        description="删除后无法恢复。"
        tone="danger"
        confirm-text="删除"
        @confirm="remove(index)"
      >
        <Button size="sm" variant="ghost" tone="neutral">删除</Button>
      </Popconfirm>
    </Inline>
    <Text v-if="!comments.length" tone="muted" size="sm">没有评论了。</Text>
  </Stack>
</template>
vue

用法

import { Popconfirm } from '@hina-ui/vue'
ts

气泡确认框在触发器旁边问一个问题,适合删除一行、撤销一次操作这类范围小、就地可见的确认;后果重、需要打断当前任务的确认用 AlertDialog。title 是问题,description 补充后果,底部一对按钮的文字可以用 cancelText 与 confirmText 替换。默认插槽是触发器。

<script setup lang="ts">
  import { ref } from 'vue'
  import { Button, Popconfirm, Stack, Text } from '@hina-ui/vue'

  const done = ref(false)
</script>

<template>
  <Stack gap="sm" align="start">
    <Popconfirm title="把全部通知标记为已读?" @confirm="done = true">
      <Button variant="outline" tone="neutral">全部已读</Button>
    </Popconfirm>
    <Text v-if="done" tone="muted" size="sm">已全部标记为已读。</Text>
  </Stack>
</template>
vue

示例

危险操作

tone="danger" 把「确定」换成危险色,用于删除这类不可撤销的操作。

<script setup lang="ts">
  import { Button, Popconfirm } from '@hina-ui/vue'
</script>

<template>
  <Popconfirm
    title="移除这位成员?"
    description="移除后对方将无法访问这个项目。"
    tone="danger"
    confirm-text="移除"
  >
    <Button variant="outline" tone="danger">移除成员</Button>
  </Popconfirm>
</template>
vue

异步确认

confirm 事件的处理函数返回 Promise 时,气泡等它结束再收回:期间「确定」显示加载指示,「取消」、Esc 与点击外部都不可用;处理函数抛出错误时气泡保持打开。

<script setup lang="ts">
  import { ref } from 'vue'
  import { Button, Popconfirm, Stack, Switch, Text } from '@hina-ui/vue'

  const fail = ref(false)
  const status = ref('')

  async function retry() {
    status.value = ''
    await new Promise(resolve => setTimeout(resolve, 1000))
    if (fail.value) {
      status.value = '重试失败,请稍后再试。'
      throw new Error('retry failed')
    }
    status.value = '已重新发送。'
  }
</script>

<template>
  <Stack gap="md" align="start">
    <Switch v-model="fail">模拟失败</Switch>
    <Popconfirm title="重新发送这封邮件?" confirm-text="重发" @confirm="retry">
      <Button variant="outline" tone="neutral">重新发送</Button>
      <template #content>
        <Text v-if="status" tone="muted" size="sm">{{ status }}</Text>
      </template>
    </Popconfirm>
  </Stack>
</template>
vue

位置

side 与 align 与 Popover 相同,默认在触发器正下方,空间不足时翻转到相反一侧。

<script setup lang="ts">
  import { Button, Inline, Popconfirm } from '@hina-ui/vue'

  const sides = ['top', 'right', 'bottom', 'left'] as const
  const names = { top: '上方', right: '右侧', bottom: '下方', left: '左侧' }
</script>

<template>
  <Inline gap="sm">
    <Popconfirm v-for="side in sides" :key="side" title="确认这个位置?" :side="side">
      <Button variant="outline" tone="neutral">{{ names[side] }}</Button>
    </Popconfirm>
  </Inline>
</template>
vue

受控

open 支持双向绑定,可以从外部打开或者收回。

<script setup lang="ts">
  import { ref } from 'vue'
  import { Button, Inline, Popconfirm } from '@hina-ui/vue'

  const open = ref(false)
</script>

<template>
  <Inline gap="sm">
    <Button variant="outline" tone="neutral" @click="open = true">从外部打开</Button>
    <Popconfirm v-model:open="open" title="清空草稿?" description="草稿里的内容会被丢弃。">
      <Button variant="outline" tone="neutral">清空草稿</Button>
    </Popconfirm>
  </Inline>
</template>
vue

行为

  • 打开后焦点落在「取消」按钮上,误按回车不会执行操作;收回后焦点回到触发器。
  • Esc 与点击外部只是收回气泡,不触发 cancel 事件;点「取消」才触发。
  • 打开期间页面停止滚动,触发器保持按下时的样式。
  • 「确定」的处理函数返回 Promise 时,气泡在其结束前处于忙碌状态,结束后收回;抛出错误则保持打开。

无障碍

  • 面板是 role="dialog",名称取自触发器,问题与说明一起关联到 aria-describedby。
  • 忙碌期间面板带有 aria-busy。
  • 按钮文字取自当前语言,可以替换。

API

Props

属性
类型
默认值
说明
title
string
—
必填。问题本身
description
string
—
补充说明
confirmText
string
当前语言
「确定」按钮的文字
cancelText
string
当前语言
「取消」按钮的文字
tone
'accent' | 'danger'
'accent'
「确定」按钮的色调
side
'top' | 'right' | 'bottom' | 'left'
'bottom'
浮出的方向
align
'start' | 'center' | 'end'
'center'
与触发器的对齐方式
sideOffset
number
8
与触发器的距离,像素
open
boolean
—
是否打开,支持双向绑定
class
string
—
追加至面板的类名

插槽

插槽
说明
default
触发器
content
说明与按钮之间的内容

事件

事件
参数
说明
confirm
—
点击「确定」;处理函数返回 Promise 时等待其完成
cancel
—
点击「取消」