Confirm 确认框
破坏性操作的二次确认。声明式与命令式两种用法。
声明式
vue
<script setup>
import { ref } from 'vue'
const visible = ref(false)
</script>
<template>
<SrButton variant="danger" @click="visible = true">删除</SrButton>
<SrConfirm
v-model="visible"
type="danger"
title="删除确认"
content="该操作不可撤销,确定继续?"
confirm-text="删除"
@confirm="handleDelete"
/>
</template>命令式
srConfirm() 返回一个 Promise,true 表示确认、false 表示取消。 调用处不需要维护 visible 状态,因此代码短得多。
vue
<script setup>
import { srConfirm } from '@starriver/ui'
async function handleDelete() {
const ok = await srConfirm({
type: 'danger',
title: '删除确认',
content: '该操作不可撤销,确定继续?',
confirmText: '删除'
})
if (!ok) return
await deleteItem()
}
</script>什么时候该用命令式
判断标准是「这个确认框和哪个组件绑定」:
| 场景 | 推荐 | 原因 |
|---|---|---|
| 确认框由某个按钮触发 | 命令式 | 不必为了它多维护一个 ref,逻辑也都在 handleDelete 里 |
| 确认框内容随状态频繁变化 | 声明式 | 命令式的参数只传一次,动态内容不好改 |
| 确认框需要在模板中定位(如自定义插槽) | 声明式 | 命令式创建在独立的挂载点上 |
命令式最常见——「点删除 → 问一下 → 真删」这类逻辑, 用命令式写出来就是几行,用声明式则需要在组件里多一个 ref、 在模板里多一个 <SrConfirm>,而且两者相隔很远。
命令式的挂载点
它在第一次调用时创建并挂到一个独立容器上(与 toast 共用机制), 因此不需要在模板里放任何东西。
SSR 环境下调用是安全的——会返回 false 而不抛错, 因为服务端渲染时用户不可能做出选择。
类型与文案
vue
<SrConfirm type="primary" confirm-text="确定" />
<SrConfirm type="warning" confirm-text="我确定" />
<SrConfirm type="danger" confirm-text="删除" danger />type 决定图标与确定按钮的配色:
| 类型 | 用途 | 确定按钮文案建议 |
|---|---|---|
primary | 中性确认 | 「确定」 |
warning | 有风险但可逆 | 「继续」 |
danger | 不可逆操作 | 用动词——「删除」「清空」 |
危险操作的按钮文案要写动词
「确定」这个词在删除场景下很糟——用户读到的是"确定要做什么", 答"确定"很自然,结果数据没了。
把按钮写成「删除」,用户按下时至少知道自己在做什么。 这也是 confirm-text 存在的原因。
单按钮模式
show-cancel="false" 只显示确定按钮,用于纯粹的通知。
vue
<SrConfirm v-model="visible" :show-cancel="false" />异步与加载态
loading 让确定按钮进入加载状态,避免重复点击。
vue
<script setup>
const visible = ref(false)
const submitting = ref(false)
async function onOk() {
submitting.value = true
try {
await submit()
visible.value = false
} finally {
submitting.value = false
}
}
</script>
<template>
<SrConfirm v-model="visible" :loading="submitting" @confirm="onOk" />
</template>命令式如何配合异步
srConfirm() 在用户点确定后立即 resolve,不等你的异步操作完成。
需要"确定后加载、完成才关闭"的效果,用声明式更顺手—— 或者在 await 之后再用命令式开一个的结果提示。
Props
| 名称 | 类型 | 默认值 | 说明 |
|---|---|---|---|
modelValue | boolean | false | 是否显示 |
title | string | — | 标题 |
content | string | — | 正文 |
type | 'primary' | 'warning' | 'danger' | 'primary' | 类型 |
confirmText | string | '确定' | 确定按钮文案 |
cancelText | string | '取消' | 取消按钮文案 |
showCancel | boolean | true | 是否显示取消按钮 |
loading | boolean | false | 确定按钮是否加载中 |
closeOnOverlay | boolean | false | 点击遮罩是否关闭(默认否) |
srConfirm(options)
接受上述 props 的子集,返回 Promise<boolean>。
ts
const ok = await srConfirm({
type: 'danger',
title: '删除确认',
content: '该操作不可撤销',
confirmText: '删除',
cancelText: '再想想'
})事件
| 事件 | 说明 |
|---|---|
confirm | 点击确定 |
cancel | 点击取消或关闭 |
update:modelValue | 显隐变化 |
无障碍
- 与
Modal相同的四要素(Teleport、层级令牌、ESC 与焦点归还、滚动锁定) - 容器带
role="alertdialog"——这比role="dialog"更准确: 它告诉读屏软件内容需要立即处理,会先朗读全文再让用户操作 - 初始焦点落在取消按钮上(危险操作时)——用户误按回车不会触发删除。 这是破坏性确认框的一个重要细节