确认弹出框 Popconfirm
一个有确认按钮的弹出框。
Popconfirm 与 Popover 在交互上类似,但更侧重于提供确认(确认/取消)类的轻量化操作。
基础使用
通过 content 属性设置显示的提示文本,默认会展示图标、文本与底部按钮(确认/取消)。
<template>
<px-space>
<px-popconfirm content="Are you sure you want to delete this item?">
<px-button theme="danger">Delete</px-button>
</px-popconfirm>
<px-popconfirm>
<template #content>
<div>
Shouldn't we make the warning mark bigger?<br />
It's hard to notice as is.
</div>
</template>
<px-button>Confirm</px-button>
</px-popconfirm>
</px-space>
</template>弹出位置
Popconfirm 弹出框提供 9 种展示位置。
由 placement 属性决定弹出的位置。该属性值格式为:[方向]-[对齐位置],分别是'top'、'right'、'bottom'、'left'、'top-start'、'top-end'、'right-start'、'right-end'、'bottom-start'、'bottom-end'、'left-start'、'left-end',有四个展示方向,和三种对齐方式,默认的 placement 为 top。
<template>
<div class="box">
<div class="left">
<px-popconfirm
v-for="item in ['left-start', 'left', 'left-end']"
:key="item"
:placement="item"
:content="getContent(item)"
>
<px-button>{{ getLabel(item) }}</px-button>
</px-popconfirm>
</div>
<div class="center">
<div class="top">
<px-popconfirm
v-for="item in ['top-start', 'top', 'top-end']"
:key="item"
:placement="item"
:content="getContent(item)"
>
<px-button>{{ getLabel(item) }}</px-button>
</px-popconfirm>
</div>
<div class="bottom">
<px-popconfirm
v-for="item in ['bottom-start', 'bottom', 'bottom-end']"
:key="item"
:placement="item"
:content="getContent(item)"
>
<px-button>{{ getLabel(item) }}</px-button>
</px-popconfirm>
</div>
</div>
<div class="right">
<px-popconfirm
v-for="item in ['right-start', 'right', 'right-end']"
:key="item"
:placement="item"
:content="getContent(item)"
>
<px-button>{{ getLabel(item) }}</px-button>
</px-popconfirm>
</div>
</div>
</template>
<script setup lang="ts">
const getLabel = (placement: string) => {
return placement.replace(/-/g, ' ').replace(/\b\w/g, (l) => l.toUpperCase())
}
const getContent = (placement: string) => {
let contentArr: string[] = []
if (placement.includes('-')) {
const [pos, sub] = placement.split('-')
contentArr = [capitalize(pos), capitalize(sub), 'Popover']
} else {
contentArr = [capitalize(placement), 'Popover']
}
return placement.startsWith('top') || placement.startsWith('bottom')
? contentArr.join(' ')
: contentArr.join('\n')
}
const capitalize = (str: string) => str.charAt(0).toUpperCase() + str.slice(1)
</script>
<style lang="css" scoped>
.box {
display: flex;
width: 600px;
height: 350px;
margin-left: 100px;
margin-top: 64px;
margin-bottom: 64px;
}
.left,
.right {
flex-shrink: 0;
display: flex;
flex-direction: column;
justify-content: space-around;
}
.left {
align-items: flex-start;
}
.right {
align-items: flex-end;
}
.center {
flex: 1;
display: flex;
flex-direction: column;
}
.top,
.bottom {
display: flex;
justify-content: space-around;
}
.top {
flex: 1;
}
</style>受控模式
传入 visible 属性进入受控模式;不传或传 undefined 则为非受控模式,可使用 defaultVisible 指定初始显示。组件会触发 update:visible 事件以配合 v-model。
<template>
<px-popconfirm content="Controlled confirm" v-model:visible="visible">
<px-button>Controlled {{ visible }}</px-button>
</px-popconfirm>
</template>
<script setup lang="ts">
import { ref } from 'vue'
const visible = ref(false)
</script>异步确认
传入 onBeforeOk 后,在确认时将会等待 onBeforeOk 执行完成,若结果不为 false 再执行后续代码。
<template>
<px-popconfirm content="This will run an async check" :onBeforeOk="beforeOk">
<px-button>Async Confirm</px-button>
</px-popconfirm>
</template>
<script setup lang="ts">
import { ref } from 'vue'
const calls = ref(0)
const beforeOk = async () => {
calls.value += 1
if (calls.value % 2 === 1) {
await new Promise((r) => setTimeout(r, 500))
return false
}
await new Promise((r) => setTimeout(r, 500))
return true
}
</script>自定义底部与图标
通过 footer 插槽可以自定义整个底部区域。若需要自定义图标,可使用 icon 插槽,showIcon 控制是否展示图标;若只需要更改按钮文字 / 属性,使用 okText、cancelText 以及 okButtonProps、cancelButtonProps。
<template>
<px-space>
<px-popconfirm content="Custom Icon example">
<template #icon>
<IconMinds />
</template>
<px-button>Custom Icon</px-button>
</px-popconfirm>
<px-popconfirm content="No Icon example" :show-icon="false">
<px-button>No Icon</px-button>
</px-popconfirm>
<px-popconfirm
content="Custom Button example"
ok-text="Yes, delete"
cancel-text="No, keep it"
cancel-button-props="{ theme: 'info' }"
ok-button-props="{ theme: 'danger' }"
>
<px-button>Custom Button</px-button>
</px-popconfirm>
<px-popconfirm content="Custom footer example" v-model:visible="visible4CustomFooter">
<template #footer> Custom Footer Content </template>
<px-button>Custom Footer</px-button>
</px-popconfirm>
</px-space>
</template>
<script setup lang="tsx">
import { ref } from 'vue'
import { IconMinds } from '@pixelium/web-vue/icon-hn/es'
const visible4CustomFooter = ref(false)
</script>禁用状态
传入 disabled 设置禁用状态,此时触发方式将失效,弹出层不会被打开。
<template>
<px-popconfirm content="This popconfirm is disabled" disabled>
<px-button>Disabled</px-button>
</px-popconfirm>
</template>API
PopconfirmProps
| 属性 | 类型 | 可选 | 默认值 | 描述 | 版本 |
|---|---|---|---|---|---|
| content | string | 是 | | 确认弹出框文本内容。 | 0.1.0 |
| visible | boolean | null | 是 | | 是否显示(受控模式,支持 v-model)。 | 0.1.0 |
| defaultVisible | boolean | null | 是 | | 非受控模式下默认的显示状态。 | 0.1.0 |
| loading | boolean | 是 | false | 传入 loading 则用于控制确认按钮 loading 状态。 | 0.1.0 |
| placement | 'top' | 'right' | 'bottom' | 'left' | 'top-start' | 'top-end' | 'right-start' | 'right-end' | 'bottom-start' | 'bottom-end' | 'left-start' | 'left-end' | 是 | 'top' | 弹出位置。 | 0.1.0 |
| okText | string | 是 | | 确认按钮文本。 | 0.1.0 |
| cancelText | string | 是 | | 取消按钮文本。 | 0.1.0 |
| showIcon | boolean | 是 | true | 是否显示默认图标。 | 0.1.0 |
| showCancel | boolean | 是 | true | 是否显示取消按钮。 | 0.1.0 |
| showFooter | boolean | 是 | true | 是否显示底部区域。 | 0.1.0 |
| offset | number | 是 | 8 | 弹出偏移距离(px)。 | 0.1.0 |
| variant | 'dark' | 'light' | 是 | 'light' | 组件样式变体。 | 0.1.0 |
| arrow | boolean | 是 | true | 是否展示箭头。 | 0.1.0 |
| disabled | boolean | 是 | false | 是否禁用。 | 0.1.0 |
| zIndex | number | 是 | | 弹出层 z-index。 | 0.1.0 |
| root | HTMLElement | string | 是 | 'body' | 挂载元素。 | 0.1.0 |
| destroyOnHide | boolean | 是 | false | 隐藏时是否销毁内容。 | 0.1.0 |
| popoverProps | Omit<PopoverProps, 'visible' | 'content' | 'defaultVisible'> & EmitEvent<PopoverEvents> | 是 | | 透传给内部 Popover 的属性。 | 0.1.0 |
| okButtonProps | ButtonProps & EmitEvent<ButtonEvents> & RestAttrs | 是 | | 传给确认按钮的属性以及事件。 | 0.1.0 |
| cancelButtonProps | ButtonProps & EmitEvent<ButtonEvents> & RestAttrs | 是 | | 传给取消按钮的属性以及事件。 | 0.1.0 |
| containerProps | RestAttrs | 是 | | 透传 DOM 属性到容器区域。 | 0.1.0 |
| contentProps | RestAttrs | 是 | | 透传 DOM 属性到内容区域容器。 | 0.1.0 |
| footerProps | RestAttrs | 是 | | 透传 DOM 属性到底部区域容器。 | 0.1.0 |
PopconfirmEvents
| 事件 | 参数 | 描述 | 版本 |
|---|---|---|---|
| update:visible | value: boolean | v-model 更新时触发。 | 0.1.0 |
| beforeOk | | 用于异步确认,需返回一个 Promise<boolean | void> | boolean | void 类型的数据判断是否成功,await 操作后不为 false 即为确认成功。 | 0.1.0 |
| ok | event: MouseEvent | 点击确认按钮时触发(在 onBeforeOk 通过时)。 | 0.1.0 |
| cancel | event: MouseEvent | KeyboardEvent | 点击取消按钮时触发。 | 0.1.0 |
| close | e: MouseEvent | 弹出层关闭时触发。 | 0.1.0 |
| open | e: MouseEvent | 弹出层打开时触发。 | 0.1.0 |
PopconfirmSlots
| 插槽 | 参数 | 描述 | 版本 |
|---|---|---|---|
| default | | 触发元素插槽。 | 0.1.0 |
| content | | 自定义内容。 | 0.1.0 |
| icon | | 自定义图标。 | 0.1.0 |
| footer | | 自定义底部。 | 0.1.0 |
PopconfirmExpose
| 属性 | 类型 | 可选 | 默认值 | 描述 | 版本 |
|---|---|---|---|---|---|
| open | () => void | 否 | | 打开确认弹出框。 | 0.1.0 |
| close | () => void | 否 | | 关闭确认弹出框。 | 0.1.0 |
RestAttrs
ts
import type { StyleValue } from 'vue'
export type VueClassValue = string | Record<string, any> | VueClassValue[]
export type VueStyleValue = StyleValue
export type RestAttrs = {
style?: VueStyleValue | null
class?: VueClassValue | null
[x: string]: any
}EmitEvent
ts
export type EmitEvent<T extends Record<string, any>> = {
[K in keyof T as `on${Capitalize<K & string>}`]?: (...args: T[K]) => void
}