反馈类

气泡确认框

目标元素的操作需要用户进一步的确认时使用。与 Popover 相比它内置了一系列可配置的操作按钮,与 Modal 相比它不强制全屏居中显示,交互也更轻量

代码演示

如何引入

<script setup lang="ts">
    import { Popconfirm } from '@fibrous/semi-ui-vue';
</script>

基本使用

Popconfirm 底层基于 Tooltip 封装,Children 支持类型同 Tooltip,注意事项详情可查阅 Tooltip注意事项

代码
<script setup lang="ts">
    import { Button, Popconfirm, Toast } from '@fibrous/semi-ui-vue';

    const onConfirm = () => {
        Toast.success('确认保存!');
    };

    const onCancel = () => {
        Toast.warning('取消保存!');
    };
</script>

<template>
    <Popconfirm @cancel="onCancel" @confirm="onConfirm">
        <Button>保存</Button>
        <template #title>确定是否要保存此修改?</template>
        <template #content>此修改将不可逆</template>
    </Popconfirm>
</template>

类型搭配

开发者可以基于场景使用 okType/cancelType 参数和 #icon 插槽搭配出不同风格的气泡式确认框。没有传入 #icon 插槽时显示默认警告图标,传入空插槽则不渲染图标。

代码
<script setup lang="ts">
    import { ref } from 'vue';
    import { IconAlertTriangle } from '@fibrous/semi-icons-vue';
    import { Button, Popconfirm, Radio, RadioGroup, type RadioValue } from '@fibrous/semi-ui-vue';

    type TypeKey = 'default' | 'warning' | 'danger' | 'tertiary';

    const typeMap: Record<TypeKey, { okType?: 'danger'; color?: string }> = {
        default: {},
        warning: { color: 'var(--semi-color-warning)' },
        danger: { okType: 'danger', color: 'var(--semi-color-danger)' },
        tertiary: { color: 'var(--semi-color-tertiary)' },
    };
    const keys = Object.keys(typeMap) as TypeKey[];
    const type = ref<TypeKey>('default');
    const visible = ref(true);

    const changeType = (value: RadioValue | undefined) => {
        const key = keys.find((item) => item === value);
        if (key) type.value = key;
    };
</script>

<template>
    <div>
        <RadioGroup :modelValue="type" :style="{ marginTop: '14px', marginBottom: '14px' }" type="button" @update:modelValue="changeType">
            <Radio v-for="key in keys" :key="key" :value="key">
                <span :style="{ color: `var(--semi-color-${key === 'default' ? 'primary' : key})` }">{{ key }}</span>
            </Radio>
        </RadioGroup>
        <div>
            <Popconfirm v-model:visible="visible" :okType="typeMap[type].okType" trigger="custom">
                <Button @click="visible = !visible">点击此处</Button>
                <template #icon>
                    <IconAlertTriangle size="extra-large" :style="{ color: typeMap[type].color }" />
                </template>
                <template #title>确定是否要保存此修改?</template>
                <template #content>此修改将不可逆</template>
            </Popconfirm>
        </div>
    </div>
</template>

延时关闭

onConfirm、onCancel 可以通过 return Promise 实现点击后延时关闭。
onCancel、onConfirm 被触发时,对应的 Button 会自动切换为 loading: true, promise solve 会关闭气泡确认框, promise reject时气泡依然保留,同时 button loading 自动切换为 false

代码
<script setup lang="ts">
    import { Button, Popconfirm } from '@fibrous/semi-ui-vue';

    const onConfirm = () =>
        new Promise<void>((resolve) => {
            setTimeout(() => {
                console.log('resolve,close popconfirm');
                resolve();
            }, 2000);
        });

    const onCancel = () =>
        new Promise<void>((_resolve, reject) => {
            setTimeout(() => {
                console.log('reject, popconfirm still exist');
                reject();
            }, 2000);
        });
</script>

<template>
    <Popconfirm @cancel="onCancel" @confirm="onConfirm">
        <Button>保存</Button>
        <template #title>确定是否要保存此修改?</template>
        <template #content>此修改将不可逆</template>
    </Popconfirm>
</template>

初始化弹出层焦点位置

okButtonProps 和 cancelButtonProps 支持传入 autoFocus 参数,传入后打开面板时会自动聚焦在该位置。

#content 插槽的作用域参数为 { initialFocusRef },用 :ref 将它绑定在可聚焦 DOM 或组件上,打开面板时会自动聚焦在该位置。同时指定按钮 autoFocus 与 initialFocusRef 时,按钮优先。

代码
<script setup lang="ts">
    import { Button, Popconfirm, Space } from '@fibrous/semi-ui-vue';
</script>

<template>
    <Space>
        <Popconfirm :okButtonProps="{ autoFocus: true, type: 'danger' }">
            <Button>确认聚焦</Button>
            <template #title>确定是否要保存此修改?</template>
            <template #content>此修改将不可逆</template>
        </Popconfirm>
        <Popconfirm :cancelButtonProps="{ autoFocus: true }">
            <Button>取消聚焦</Button>
            <template #title>确定是否要保存此修改?</template>
            <template #content>此修改将不可逆</template>
        </Popconfirm>
        <Popconfirm>
            <Button>内容聚焦</Button>
            <template #title>确定是否要保存此修改?</template>
            <template #content="{ initialFocusRef }">
                <input :ref="initialFocusRef" placeholder="focus here" />
            </template>
        </Popconfirm>
    </Space>
</template>

搭配 Tooltip 或 Popover 使用

请参考搭配使用

API 参考

Props

属性说明类型默认值
cancelButtonProps取消按钮的属性,autoFocus 为 true 时打开后聚焦该按钮,class、style 落在按钮上。PopconfirmButtonPropssemiGlobalDefault("Popconfirm", "cancelButtonProps")
cancelText取消按钮文字,缺省取语言包 Popconfirm.cancel。stringsemiGlobalDefault("Popconfirm", "cancelText")
cancelType取消按钮类型。TypesemiDefault("Popconfirm", "cancelType", "tertiary")
defaultVisible非受控时初始是否展示。booleansemiGlobalDefault("Popconfirm", "defaultVisible")
disabled是否禁用;禁用时只渲染触发元素,不弹出确认框。booleansemiDefault("Popconfirm", "disabled", false)
okButtonProps确认按钮的属性,autoFocus 为 true 时打开后聚焦该按钮,class、style 落在按钮上。PopconfirmButtonPropssemiGlobalDefault("Popconfirm", "okButtonProps")
okText确认按钮文字,缺省取语言包 Popconfirm.confirm(zh_CN 为「确定」)。stringsemiGlobalDefault("Popconfirm", "okText")
okType确认按钮类型。TypesemiDefault("Popconfirm", "okType", "primary")
showCloseIcon是否显示右上角关闭按钮。booleansemiDefault("Popconfirm", "showCloseIcon", true)
title纯文本标题,同时作为对话框的可访问名称;同时传入 #title 插槽时以插槽为准。声明为 prop,不会作为原生 title 属性落到元素上。stringundefined
onCancel点击取消按钮或关闭按钮的回调;返回 Promise 时按钮保持加载,落定后才关闭,reject 时保留确认框;保留为函数 prop 以读取返回值。Type((event: MouseEvent) => void | Promise<unknown>)undefined
onConfirm点击确认按钮的回调;返回 Promise 时按钮保持加载,落定后才关闭,reject 时保留确认框;保留为函数 prop 以读取返回值。Type((event: MouseEvent) => void | Promise<unknown>)undefined
ariaLabel对话框的 aria-label,传入后优先于标题。stringsemiGlobalDefault("Popconfirm", "ariaLabel")
ariaLabelledby对话框的 aria-labelledby,缺省指向标题,没有标题时指向内容。stringsemiGlobalDefault("Popconfirm", "ariaLabelledby")
ariaDescribedby对话框的 aria-describedby,缺省在同时有标题和内容时指向内容。stringsemiGlobalDefault("Popconfirm", "ariaDescribedby")
role弹出层的 ARIA role,缺省为 dialog。stringsemiDefault("Popconfirm", "role", "dialog")
autoAdjustOverflow弹出层被遮挡时是否自动调整方向。booleansemiGlobalDefault("Popconfirm", "autoAdjustOverflow")
visible是否展示,配合 v-model:visible 使用;传入后由该值决定显示,trigger 保持原值,触发器事件仍然生效。booleansemiGlobalDefault("Popconfirm", "visible")
position弹出方向,缺省为 bottomLeft(RTL 下为 bottomRight)。Type"top" | "bottom" | "left" | "right" | "topLeft" | "topRight" | "leftTop" | "leftBottom" | "rightTop" | "rightBottom" | "bottomLeft" | "bottomRight" | "leftTopOver" | "rightTopOver" | "leftBottomOver" | "rightBottomOver"semiGlobalDefault("Popconfirm", "position")
motion是否展示弹出动画。booleansemiGlobalDefault("Popconfirm", "motion")
mouseEnterDelay指针移入后延迟显示的毫秒数,仅 trigger 为 hover 或 focus 时生效。numbersemiGlobalDefault("Popconfirm", "mouseEnterDelay")
mouseLeaveDelay指针移出后延迟隐藏的毫秒数,仅 trigger 为 hover 或 focus 时生效。numbersemiGlobalDefault("Popconfirm", "mouseLeaveDelay")
trigger触发展示的时机,可选 hover、focus、click、contextMenu 或 custom。"hover" | "focus" | "click" | "custom" | "contextMenu"semiDefault("Popconfirm", "trigger", "click")
contentClassName内容容器的类名。string | unknown[]semiGlobalDefault("Popconfirm", "contentClassName")
showArrow是否显示箭头三角形。booleansemiGlobalDefault("Popconfirm", "showArrow")
spacing弹出层与触发元素的距离,单位为像素;对象形式分别设置水平与垂直方向。number | { x: number; y: number; }semiGlobalDefault("Popconfirm", "spacing")
stopPropagation是否阻止弹出层上的 click、mousedown 与焦点进出事件冒泡;确认卡片内的 click 始终不冒泡。string | booleansemiDefault("Popconfirm", "stopPropagation", true)
arrowStyle箭头的边框色、背景色与边框透明度。ArrowStylesemiGlobalDefault("Popconfirm", "arrowStyle")
arrowPointAtCenter箭头是否指向触发元素中心,需要同时开启 showArrow。booleansemiGlobalDefault("Popconfirm", "arrowPointAtCenter")
prefixCls确认卡片的类名前缀。stringsemiDefault("Popconfirm", "prefixCls", cssClasses.PREFIX)
closeOnEsc弹出层打开期间按 Esc 是否关闭确认框;trigger 为 custom 时只触发 escKeyDown,由使用方决定是否关闭。booleansemiGlobalDefault("Popconfirm", "closeOnEsc")
guardFocus焦点位于确认框内时,Tab 是否在其中循环。booleansemiGlobalDefault("Popconfirm", "guardFocus")
returnFocusOnClose关闭后焦点是否回到触发元素;受控的 visible 也照常生效,trigger 为 custom 时不生效。booleansemiGlobalDefault("Popconfirm", "returnFocusOnClose")
clickToHide点击弹出层及其内部任一元素时是否关闭。booleansemiGlobalDefault("Popconfirm", "clickToHide")
disableArrowKeyDown是否禁用在触发元素上按方向键把焦点移入确认框。booleansemiGlobalDefault("Popconfirm", "disableArrowKeyDown")
disableFocusListenertrigger 为 hover 时,是否不响应键盘聚焦打开。booleansemiGlobalDefault("Popconfirm", "disableFocusListener")
keepDOM关闭时是否保留内容而不销毁。booleansemiGlobalDefault("Popconfirm", "keepDOM")
condition是否允许触发显示;仅显式设为 false 时,hover、click、focus 等触发行为不生效。由 true 变为 false 时立即关闭已显示的确认框;visible 受控时只发出 update:visible 与 visibleChange(false),使用方回写后才关闭。booleansemiGlobalDefault("Popconfirm", "condition")

Events

事件说明回调参数
open确认框显示、进场动画开始时触发,每次打开一次,早于 afterOpen,受控与非受控相同;悬停打开后指针已离开而撤回的打开不触发。[]
update:visible需要显示或隐藏时触发,供 v-model:visible 回写。[visible: boolean]
visibleChange显示状态变化时触发;用户点击触发器后早于确认框出现。visible 受控时只报告用户交互发起的请求,父组件自己改变 visible 不触发。[visible: boolean]
clickOutSide确认框打开时在触发元素与确认框以外的区域按下鼠标时触发,仅 trigger 为 click、contextMenu 或 custom 时有效。[event: MouseEvent]
escKeyDowncloseOnEsc 为 true(缺省)时,确认框打开期间按 Esc 触发。[event: KeyboardEvent]
afterOpen确认框打开且进场动画结束后触发;没有进场动画时打开后即触发,受控与非受控相同;进场结束前被关闭的打开不触发。[]
afterClose确认框关闭且离场动画结束后触发。[]

Slots

插槽说明作用域参数
default触发元素。any
title确认框标题。any
content确认框内容,作用域参数 initialFocusRef 绑定到打开时需要聚焦的元素;空插槽不渲染内容区。TypeRenderContentProps<FocusTarget>
icon自定义图标;不传时显示默认警告图标,传入空插槽则不渲染图标。any

Exposes

名称说明类型
focusTrigger让触发元素获得焦点,仅在 returnFocusOnClose 为 true 且 trigger 不是 custom 时生效;disabled 时调用无效果。Type() => void

class、style 落在确认卡片上,okButtonProps、cancelButtonProps 中的 class、style 落在按钮上;其他未声明的属性会被丢弃。aria-label、aria-labelledby、aria-describedby 是声明的 props,落在 role="dialog" 元素上。所在子树被 <KeepAlive> 缓存(失活)时,弹出层按关闭处理并通知 update:visible、visibleChange(false);单向绑定 visible 为 true 的弹出层随缓存的子树隐藏,重新激活后再次显示。

visible 受控时点击或悬停触发器会发出 update:visible 与 visibleChange,由使用方通过 v-model:visible 回写;父组件自己改变 visible 不发出这两个事件,returnFocusOnClose 照常生效。单向受控(只传 :visible 不回写)时,确认或取消不会立即把焦点还给触发器,焦点在确认框真正关闭时才回去。

Accessibility

ARIA

  • 无论 trigger 是什么(包括 hover、focus),Popconfirm 的弹出层都具有 dialog role,以 title 命名(没有 title 时以 content 命名);可用 role 属性覆盖
  • 其余语义化请参考 Popover

键盘和焦点

  • Popconfirm 必须带有触发器,触发器可被聚焦,使用 Enter 键打开 Popconfirm
  • Popconfirm 激活后,按下方向键 ⬇️ 将焦点移动到 Popconfirm 上。Popconfirm 的初始焦点应当遵循以下几个原则:
    • 如果 Popconfirm 内包含一个不可逆转过程的最后一个步骤,比如:删除数据等,那么这个初始焦点最好放在破坏性最小的可交互元素上,如:关闭按钮 ( 通过向对象 cancelButtonProps 中传入 autoFocus 实现)
    • 如果 Popconfirm 内仅为阅读文本,那么建议将初始焦点设置在最可能常用的交互元素上,如:确定按钮 ( 通过向对象 okButtonProps 中传入 autoFocus 实现)
  • 键盘用户能够通过按 Esc 关闭 Popconfirm,并且焦点应该返回到触发器上。用户通过 Popconfirm 内的交互元素关闭该 Pop 后,焦点也应当返回到触发器上(trigger 为 custom 时除外)
  • 打开的情况下,用户点击 Popconfirm 内的空白处 Esc 后,焦点也会回到触发器上 (trigger 为 custom 时除外)

设计变量

下表是组件内部的 Sass 变量,不能覆写。定制样式请覆写 --semi-* CSS 变量(见 Design Token 页),或写不分层的 CSS 规则。
Sass 变量值用法
$color-popconfirm_header-textvar(--semi-color-text-0)标题文字颜色
$color-popconfirm_body-textvar(--semi-color-text-2)正文文字颜色
$color-popconfirm_header_alert-iconvar(--semi-color-warning)警示图标颜色
$width-popconfirm-icon24px图标宽度
$width-popconfirm-maxWidth400px整体最大宽度
$spacing-popconfirm-top24px顶部内边距
$spacing-popconfirm-bottom20px底部内边距
$spacing-popconfirm_with_arrow-padding12px顶部内边距
$spacing-popconfirm_header_title-marginBottom8pxheader 标题底部外边距
$spacing-popconfirm_body_p-padding0body 正文内边距
$spacing-popconfirm_body_p-margin0body 正文外边距
$spacing-popconfirm_footer-marginTop25pxfooter 顶部外边距
$spacing-popconfirm_footer_btn-marginRight8pxfooter 按钮右侧外边距
$spacing-popconfirm_popover_with_arrow_inner-padding($spacing-popconfirm-top - $spacing-popconfirm_with_arrow-padding) ($spacing-popconfirm-top - $spacing-popconfirm_with_arrow-padding) ($spacing-popconfirm-top - $spacing-popconfirm_with_arrow-padding) ($spacing-popconfirm-bottom - $spacing-popconfirm_with_arrow-padding)带三角形箭头时的内边距
$spacing-popconfirm_popover_with_arrow_inner_rtl-padding($spacing-popconfirm-top - $spacing-popconfirm_with_arrow-padding) ($spacing-popconfirm-bottom - $spacing-popconfirm_with_arrow-padding) ($spacing-popconfirm-top - $spacing-popconfirm_with_arrow-padding) ($spacing-popconfirm-top - $spacing-popconfirm_with_arrow-padding)带三角形箭头时的内边距(rtl)
$spacing-popconfirm_header_icon-marginRight12pxheader 图标的右侧外边距
$font-popconfirm_header_title-fontWeight$font-weight-boldheader 标题字重
$radius-popconfirm-popovervar(--semi-border-radius-medium)气泡确认框圆角大小

FAQ

  • 为什么 Popconfirm 浮层在靠近屏幕边界宽度不够时,丢失宽度意外换行?
    在 chromium 104 后 对于屏幕边界文本宽度不够时的换行渲染策略发生变化,详细原因可查看 issue #1022,semi侧已经在v2.17.0版本修复了这个问题。