Snackbar 底部通知
单行胶囊通知,自带 action 按钮(如 Undo),支持 6 种位置。
基础用法
与 Toast 区别:单行、胶囊形、带 action。常用场景:删除后的”撤销”。
背景 视口
<script setup lang="ts">
import { ref } from 'vue';
import { CfSnackbar, CfButton } from '@chufix-design/vue';
const open = ref(false);
</script>
<template>
<div class="demo-row">
<CfButton @click="open = true">删除一项</CfButton>
<CfSnackbar
v-model:open="open"
tone="success"
message="Deleted login.request"
action-label="撤销"
action-shortcut="⌘Z"
@action="open = false"
/>
</div>
</template> <script setup>
import { ref } from 'vue';
import { CfSnackbar, CfButton } from '@chufix-design/vue';
const open = ref(false);
</script>
<template>
<div class="demo-row">
<CfButton @click="open = true">删除一项</CfButton>
<CfSnackbar
v-model:open="open"
tone="success"
message="Deleted login.request"
action-label="撤销"
action-shortcut="⌘Z"
@action="open = false"
/>
</div>
</template> import { useState } from 'react';
import { CfButton, CfSnackbar } from '@chufix-design/react';
export default function Demo() {
const [open, setOpen] = useState(false);
return (
<>
<div className="demo-row">
<CfButton onClick={() => setOpen(true)}>删除一项</CfButton>
<CfSnackbar open={open} onOpenChange={setOpen} tone="success" message="Deleted login.request" action-label="撤销" action-shortcut="⌘Z" onAction={() => setOpen(false)}
/>
</div>
</>
);
} import { useState } from 'react';
import { CfButton, CfSnackbar } from '@chufix-design/react';
export default function Demo() {
const [open, setOpen] = useState(false);
return (
<>
<div className="demo-row">
<CfButton onClick={() => setOpen(true)}>删除一项</CfButton>
<CfSnackbar open={open} onOpenChange={setOpen} tone="success" message="Deleted login.request" action-label="撤销" action-shortcut="⌘Z" onAction={() => setOpen(false)}
/>
</div>
</>
);
} 6 种 placement
默认 bottom-center,常用替代是 top-right(不挡底部内容)。
背景 视口
<script setup lang="ts">
import { ref } from 'vue';
import { CfSnackbar, CfButton } from '@chufix-design/vue';
import type { SnackbarPlacement } from '@chufix-design/vue';
const open = ref(false);
const placement = ref<SnackbarPlacement>('bottom-center');
function show(p: SnackbarPlacement) {
placement.value = p;
open.value = false;
setTimeout(() => { open.value = true; }, 50);
}
const placements: SnackbarPlacement[] = [
'bottom-center', 'bottom-left', 'bottom-right',
'top-center', 'top-left', 'top-right',
];
</script>
<template>
<div>
<div class="demo-row" style="flex-wrap: wrap;">
<CfButton v-for="p in placements" :key="p" size="sm" @click="show(p)">{{ p }}</CfButton>
</div>
<CfSnackbar
v-model:open="open"
:placement="placement"
tone="info"
:message="`Placement: ${placement}`"
/>
</div>
</template> <script setup>
import { ref } from 'vue';
import { CfSnackbar, CfButton } from '@chufix-design/vue';
const open = ref(false);
const placement = ref<SnackbarPlacement>('bottom-center');
function show(p) {
placement.value = p;
open.value = false;
setTimeout(() => { open.value = true; }, 50);
}
const placements= [
'bottom-center', 'bottom-left', 'bottom-right',
'top-center', 'top-left', 'top-right',
];
</script>
<template>
<div>
<div class="demo-row" style="flex-wrap: wrap;">
<CfButton v-for="p in placements" :key="p" size="sm" @click="show(p)">{{ p }}</CfButton>
</div>
<CfSnackbar
v-model:open="open"
:placement="placement"
tone="info"
:message="`Placement: ${placement}`"
/>
</div>
</template> import { useState } from 'react';
import { CfButton, CfSnackbar } from '@chufix-design/react';
export default function Demo() {
const [open, setOpen] = useState(false);
const [placement, setPlacement] = useState<SnackbarPlacement>('bottom-center');
function show(p: SnackbarPlacement) {
setPlacement(p);
setOpen(false);
setTimeout(() => { setOpen(true); }, 50);
}
const placements: SnackbarPlacement[] = [
'bottom-center', 'bottom-left', 'bottom-right',
'top-center', 'top-left', 'top-right',
];
return (
<>
<div>
<div className="demo-row" style={{ flexWrap: "wrap" }}>
<CfButton v-for="p in placements" key={p} size="sm" onClick={() => show(p)}>{p}</CfButton>
</div>
<CfSnackbar open={open} onOpenChange={setOpen} placement={placement} tone="info" message={`Placement: ${placement}`} />
</div>
</>
);
} import { useState } from 'react';
import { CfButton, CfSnackbar } from '@chufix-design/react';
export default function Demo() {
const [open, setOpen] = useState(false);
const [placement, setPlacement] = useState<SnackbarPlacement>('bottom-center');
function show(p) {
setPlacement(p);
setOpen(false);
setTimeout(() => { setOpen(true); }, 50);
}
const placements= [
'bottom-center', 'bottom-left', 'bottom-right',
'top-center', 'top-left', 'top-right',
];
return (
<>
<div>
<div className="demo-row" style={{ flexWrap: "wrap" }}>
<CfButton v-for="p in placements" key={p} size="sm" onClick={() => show(p)}>{p}</CfButton>
</div>
<CfSnackbar open={open} onOpenChange={setOpen} placement={placement} tone="info" message={`Placement: ${placement}`} />
</div>
</>
);
} API
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
open / v-model:open | boolean | — | |
tone | 'default' | 'success' | 'warning' | 'error' | 'info' | 'default' | 含图标 |
placement | 'bottom-center' | 'bottom-left' | 'bottom-right' | 'top-center' | 'top-left' | 'top-right' | 'bottom-center' | |
duration | number | 5000 | ms,0 不自动关 |
actionLabel | string | — | 操作按钮文案 |
actionShortcut | string | — | 操作右侧快捷键 |
showDismiss | boolean | true | 显示 × 按钮 |
反馈与讨论
Snackbar 底部通知 的讨论