代码演示
如何引入
import { Button, Popconfirm, Radio, RadioGroup, Space, Toast } from '@fibrous/semi-ui-solid';
基本使用
Popconfirm 底层基于 Tooltip 封装,Children 支持类型同 Tooltip,注意事项详情可查阅 Tooltip注意事项
代码
import { Button, Popconfirm, Toast } from '@fibrous/semi-ui-solid';
export default function PopconfirmDemo() {
const onConfirm = () => {
Toast.success('确认保存!');
};
const onCancel = () => {
Toast.warning('取消保存!');
};
return (
<Popconfirm title="确定是否要保存此修改?" content="此修改将不可逆" onConfirm={onConfirm} onCancel={onCancel}>
{(trigger) => <Button {...trigger()}>保存</Button>}
</Popconfirm>
);
}类型搭配
开发者可以基于场景使用 okType、cancelType 和 icon 参数搭配出不同风格的气泡式确认框。icon 接收 JSX 元素,传入 null 或 false 时不显示图标。
代码
import { createSignal, For } from 'solid-js';
import { IconAlertTriangle } from '@fibrous/semi-icons-solid';
import { Button, Popconfirm, Radio, RadioGroup, type RadioChangeEvent } from '@fibrous/semi-ui-solid';
type TypeKey = 'default' | 'warning' | 'danger' | 'tertiary';
const keys: TypeKey[] = ['default', 'warning', 'danger', 'tertiary'];
// The default icon keeps its theme color, so no color is set for it
const iconColors: Record<TypeKey, string | undefined> = {
default: undefined,
warning: 'var(--semi-color-warning)',
danger: 'var(--semi-color-danger)',
tertiary: 'var(--semi-color-tertiary)',
};
export default function PopconfirmDemo() {
const [type, setType] = createSignal<TypeKey>('default');
const [visible, setVisible] = createSignal(true);
const changeType = (event: RadioChangeEvent) => {
const key = keys.find((item) => item === event.target.value);
if (key) {
setType(key);
}
};
return (
<div>
<RadioGroup type="button" onChange={changeType} value={type()} style={{ 'margin-top': '14px', 'margin-bottom': '14px' }}>
<For each={keys}>
{(key) => (
<Radio value={key}>
<span style={{ color: `var(--semi-color-${key === 'default' ? 'primary' : key})` }}>{key}</span>
</Radio>
)}
</For>
</RadioGroup>
<div>
<Popconfirm visible={visible()} onVisibleChange={(value) => setVisible(value)} trigger="custom" okType={type() === 'danger' ? 'danger' : 'primary'} icon={<IconAlertTriangle size="extra-large" style={{ color: iconColors[type()] }} />} title="确定是否要保存此修改?" content="此修改将不可逆">
{(trigger) => (
<Button {...trigger()} onClick={() => setVisible(!visible())}>
点击此处
</Button>
)}
</Popconfirm>
</div>
</div>
);
}延时关闭
onConfirm、onCancel 可以通过 return Promise 实现点击后延时关闭。
onCancel、onConfirm 被触发时,对应的 Button 会自动切换为 loading: true, promise solve 会关闭气泡确认框, promise reject时气泡依然保留,同时 button loading 自动切换为 false
代码
import { Button, Popconfirm } from '@fibrous/semi-ui-solid';
export default function PopconfirmDemo() {
const onConfirm = () => {
return new Promise<void>((resolve) => {
setTimeout(() => {
console.log('resolve,close popconfirm');
resolve();
}, 2000);
});
};
const onCancel = () => {
return new Promise((_resolve, reject) => {
setTimeout(() => {
console.log('reject, popconfirm still exist');
reject();
}, 2000);
});
};
return (
<Popconfirm title="确定是否要保存此修改?" content="此修改将不可逆" onConfirm={onConfirm} onCancel={onCancel}>
{(trigger) => <Button {...trigger()}>保存</Button>}
</Popconfirm>
);
}初始化弹出层焦点位置
okButtonProps 和 cancelButtonProps 支持传入 autoFocus 参数,传入后打开面板时会自动聚焦在该位置。
content 支持传入函数,入参 { initialFocusRef } 中的 initialFocusRef 是 ref 回调,用 ref={initialFocusRef} 绑定在可聚焦 DOM 或组件上,打开面板时会自动聚焦在该位置。同时指定按钮 autoFocus 与 initialFocusRef 时,按钮优先。
代码
import { Button, Popconfirm, Space } from '@fibrous/semi-ui-solid';
export default function PopconfirmDemo() {
return (
<Space>
<Popconfirm title="确定是否要保存此修改?" content="此修改将不可逆" okButtonProps={{ autoFocus: true, type: 'danger' }}>
{(trigger) => <Button {...trigger()}>确认聚焦</Button>}
</Popconfirm>
<Popconfirm title="确定是否要保存此修改?" content="此修改将不可逆" cancelButtonProps={{ autoFocus: true }}>
{(trigger) => <Button {...trigger()}>取消聚焦</Button>}
</Popconfirm>
<Popconfirm title="确定是否要保存此修改?" content={(renderProps) => <input ref={renderProps.initialFocusRef} placeholder="focus here" />}>
{(trigger) => <Button {...trigger()}>内容聚焦</Button>}
</Popconfirm>
</Space>
);
}搭配 Tooltip 或 Popover 使用
请参考搭配使用
API 参考
Props
| 属性 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| afterClose | 确认框关闭且离场动画结束后调用。 | Type() => void | - |
| afterOpen | 确认框打开且进场动画结束后调用;没有进场动画时打开后即调用,受控与非受控相同;进场结束前被关闭的打开不调用。 | TooltipProps['afterOpen'] | - |
| aria-label | 对话框的 aria-label,传入后优先于标题。 | string | - |
| aria-labelledby | 对话框的 aria-labelledby,缺省指向标题,没有标题时指向内容。 | string | - |
| arrowPointAtCenter | 箭头是否指向触发元素中心,需要同时开启 showArrow,缺省为 true。 | boolean | - |
| arrowStyle | 箭头的边框色、背景色与边框透明度。 | ArrowStyle | - |
| autoAdjustOverflow | 弹出层被遮挡时是否自动调整方向,缺省为 true。 | boolean | - |
| cancelButtonProps | 取消按钮的属性。autoFocus 为 true 时打开后聚焦该按钮,class、style 与其他属性落在按钮上。 | PopconfirmButtonProps | - |
| cancelText | 取消按钮文字,缺省取语言包 Popconfirm.cancel。 | string | - |
| cancelType | 取消按钮类型,缺省为 tertiary。 | ButtonType | "tertiary" |
| children | 触发元素,使用函数形式 (getTriggerProps) => JSX.Element,在触发元素上展开 {...getTriggerProps()},让它获得聚焦、键盘与 ARIA 属性;其他写法会被包在 Tooltip 的 span 中。 | TooltipProps['children'] | - |
| class | 确认卡片(.semi-popconfirm)的类名,不落在弹出层上。 | string | - |
| clickToHide | 点击弹出层及其内部任一元素时是否关闭。 | TooltipProps['clickToHide'] | - |
| closeOnEsc | 弹出层打开期间按 Esc 是否关闭确认框,与焦点位置无关,缺省为 true;trigger 为 custom 时只调用 onEscKeyDown,由使用方决定是否关闭。 | TooltipProps['closeOnEsc'] | - |
| condition | 是否允许触发显示,缺省为 true;仅显式设为 false 时,hover、click、focus 等触发行为不生效。由 true 变为 false 时立即关闭已显示的确认框;visible 受控时只通过 onVisibleChange 请求关闭,使用方回写后才关闭。 | boolean | - |
| content | 确认框内容,可以是 JSX 元素,也可以是函数。函数的参数是 { initialFocusRef },把 initialFocusRef 作为 ref 绑定到打开时需要聚焦的元素上。 | TooltipProps['content'] | - |
| contentClassName | 内容容器的类名。 | ClassValue | - |
| defaultVisible | 非受控时初始是否展示。 | boolean | - |
| disableArrowKeyDown | 是否禁用在触发元素上按方向键把焦点移入确认框。 | TooltipProps['disableArrowKeyDown'] | - |
| disabled | 是否禁用,缺省为 false;禁用时只渲染触发元素,不弹出确认框。 | boolean | false |
| disableFocusListener | trigger 为 hover 时,是否不响应键盘聚焦打开。 | boolean | - |
| guardFocus | 焦点位于确认框内时,Tab 是否在其中循环,缺省为 true。 | TooltipProps['guardFocus'] | - |
| icon | 自定义图标,接受 JSX 元素。未传入时显示默认警告图标;传入 null 或 false 时不显示图标。 | JSX.Element | - |
| keepDOM | 关闭时是否保留内容而不销毁。 | boolean | - |
| motion | 弹出层出现与隐藏时是否有动画,缺省为 true。 | boolean | - |
| mouseEnterDelay | 指针移入后延迟显示的毫秒数,仅 trigger 为 hover 或 focus 时生效。 | number | - |
| mouseLeaveDelay | 指针移出后延迟隐藏的毫秒数,仅 trigger 为 hover 或 focus 时生效。 | number | - |
| okButtonProps | 确认按钮的属性。autoFocus 为 true 时打开后聚焦该按钮,class、style 与其他属性落在按钮上。 | PopconfirmButtonProps | - |
| okText | 确认按钮文字,缺省取语言包 Popconfirm.confirm(zh_CN 为 确定)。 | string | - |
| okType | 确认按钮类型,缺省为 primary。 | ButtonType | "primary" |
| onCancel | 点击取消按钮或关闭按钮时调用,参数是原生 MouseEvent。返回 Promise 时按钮保持加载,落定后才关闭确认框,reject 时保留确认框;返回其他值会被忽略。 | Type(e: MouseEvent) => unknown | - |
| onClickOutSide | 弹出层处于展示状态时,点击非触发元素、非弹层内部的区域时调用,参数是原生 MouseEvent。 | TooltipProps['onClickOutSide'] | - |
| onConfirm | 点击确认按钮时调用,参数是原生 MouseEvent。返回 Promise 时按钮保持加载,落定后才关闭确认框,reject 时保留确认框;返回其他值会被忽略。 | Type(e: MouseEvent) => unknown | - |
| onEscKeyDown | 弹出层打开期间按 Esc 时调用,参数是原生 KeyboardEvent。 | TooltipProps['onEscKeyDown'] | - |
| onOpen | 确认框显示、进场动画开始时调用,每次打开一次,早于 afterOpen,受控与非受控相同;悬停打开后指针已离开而撤回的打开不调用。 | TooltipProps['onOpen'] | - |
| onVisibleChange | 显示状态请求变化时调用,参数是请求的显示状态。visible 受控时只报告用户交互发起的请求,使用方自己改变 visible 不触发。 | Type(visible: boolean) => void | - |
| position | 弹出方向,缺省为 bottomLeft(RTL 下为 bottomRight)。 | Position | - |
| prefixCls | 确认卡片的类名前缀,缺省为 semi-popconfirm。 | string | "semi-popconfirm" |
| ref | 接收句柄的回调,句柄只有 focusTrigger 方法;组件创建时调用一次。 | TypeRef<PopconfirmHandle> | - |
| returnFocusOnClose | 关闭后焦点是否回到触发元素,缺省为 true;trigger 为 custom 时不生效,受控的 visible 照常生效。 | TooltipProps['returnFocusOnClose'] | - |
| role | 弹出层的 ARIA role,缺省为 dialog,与 trigger 无关。 | string | "dialog" |
| showArrow | 是否显示箭头三角形,缺省为 false。 | boolean | - |
| showCloseIcon | 是否显示右上角关闭按钮,缺省为 true。关闭按钮触发 onCancel。 | boolean | true |
| spacing | 弹出层与触发元素的距离,单位为像素;对象形式分别设置水平与垂直方向。 | number | { x: number; y: number } | - |
| stopPropagation | 是否阻止弹出层上的点击事件冒泡,缺省为 true。确认卡片内的点击始终不会传到文档上的监听器。 | boolean | string | true |
| style | 确认卡片的样式,接受对象(键为 kebab-case)或字符串。 | JSX.CSSProperties | string | - |
| title | 标题,可以是字符串或 JSX 元素。有标题时,对话框以标题命名(见 aria-labelledby)。 | JSX.Element | - |
| trigger | 触发展示的时机,可选 hover、focus、click、contextMenu 或 custom,缺省为 click。visible 受控时,触发器事件只通过 onVisibleChange 请求打开或关闭。 | Trigger | "click" |
| visible | 受控的展示状态。传入后由该值决定是否显示;点击触发器、确认、取消、点击外部与 Esc 只通过 onVisibleChange 请求变化,由使用方回写 visible 后才生效。 | boolean | - |
Methods
| 方法 | 说明 | 类型 |
|---|---|---|
| focusTrigger | 让触发元素获得焦点。仅在 returnFocusOnClose 为 true 且 trigger 不是 custom 时生效;disabled 时没有触发元素可聚焦,调用无效果。 | Type() => void |
class 与 style 落在确认卡片上,okButtonProps、cancelButtonProps 中的属性落在对应按钮上(autoFocus 除外);ref 收到 focusTrigger 句柄。Popconfirm 没有根 DOM 元素,其他未声明的原生属性和事件会被丢弃。
Accessibility
ARIA
- 无论 trigger 是什么(包括 hover、focus),Popconfirm 的弹出层都具有
dialogrole,以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 变量 | 值 | 用法 |
|---|---|---|
| $color-popconfirm_header-text | var(--semi-color-text-0) | 标题文字颜色 |
| $color-popconfirm_body-text | var(--semi-color-text-2) | 正文文字颜色 |
| $color-popconfirm_header_alert-icon | var(--semi-color-warning) | 警示图标颜色 |
| $width-popconfirm-icon | 24px | 图标宽度 |
| $width-popconfirm-maxWidth | 400px | 整体最大宽度 |
| $spacing-popconfirm-top | 24px | 顶部内边距 |
| $spacing-popconfirm-bottom | 20px | 底部内边距 |
| $spacing-popconfirm_with_arrow-padding | 12px | 顶部内边距 |
| $spacing-popconfirm_header_title-marginBottom | 8px | header 标题底部外边距 |
| $spacing-popconfirm_body_p-padding | 0 | body 正文内边距 |
| $spacing-popconfirm_body_p-margin | 0 | body 正文外边距 |
| $spacing-popconfirm_footer-marginTop | 25px | footer 顶部外边距 |
| $spacing-popconfirm_footer_btn-marginRight | 8px | footer 按钮右侧外边距 |
| $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-marginRight | 12px | header 图标的右侧外边距 |
| $font-popconfirm_header_title-fontWeight | $font-weight-bold | header 标题字重 |
| $radius-popconfirm-popover | var(--semi-border-radius-medium) | 气泡确认框圆角大小 |
FAQ
- 为什么 Popconfirm 浮层在靠近屏幕边界宽度不够时,丢失宽度意外换行?
在 chromium 104 后 对于屏幕边界文本宽度不够时的换行渲染策略发生变化,详细原因可查看 issue #1022,semi侧已经在v2.17.0版本修复了这个问题。