20260816220132
This commit is contained in:
1 parent
b6f9a4c912
commit
72993ecdcd
179 files changed
+20050
-633
No files matched your search
@@ -0,0 +1,153 @@
|
||||
<script setup>
|
||||
import MessageItem from './message.vue'
|
||||
import { messageState } from './message-store.js'
|
||||
|
||||
/* 9 个方位:分组容器始终存在,仅消息项进出,保证 enter/leave 动画稳定触发 */
|
||||
const PLACEMENTS = [
|
||||
'top-left', 'top-center', 'top-right',
|
||||
'center-left', 'center', 'center-right',
|
||||
'bottom-left', 'bottom-center', 'bottom-right',
|
||||
]
|
||||
|
||||
/* ---------- 关闭某条 ---------- */
|
||||
function close(id) {
|
||||
const idx = messageState.items.findIndex((i) => i.id === id)
|
||||
if (idx !== -1) messageState.items.splice(idx, 1)
|
||||
}
|
||||
|
||||
/* ---------- 方位 → flex 对齐类 ---------- */
|
||||
function placementClasses(p) {
|
||||
const v = p.split('-')[0]
|
||||
const h = p.split('-')[1] || 'center'
|
||||
return [
|
||||
`fms-placement-${v === 'center' ? 'center-v' : v}`,
|
||||
`fms-placement-${h === 'center' ? 'center-h' : h}`,
|
||||
]
|
||||
}
|
||||
|
||||
/* 某个方位下当前存活的消息 */
|
||||
function itemsOf(p) {
|
||||
return messageState.items.filter(
|
||||
(i) => (i.placement || messageState.placement || 'top-center') === p,
|
||||
)
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Teleport to="body">
|
||||
<div class="fms-message-container" aria-live="polite">
|
||||
<TransitionGroup
|
||||
v-for="p in PLACEMENTS"
|
||||
:key="p"
|
||||
name="fms-message"
|
||||
tag="div"
|
||||
:class="['fms-message-list', ...placementClasses(p)]"
|
||||
>
|
||||
<MessageItem
|
||||
v-for="item in itemsOf(p)"
|
||||
:key="item.id"
|
||||
:id="item.id"
|
||||
:type="item.type"
|
||||
:content="item.content"
|
||||
:duration="item.duration"
|
||||
:closable="item.closable"
|
||||
@close="close(item.id)"
|
||||
/>
|
||||
</TransitionGroup>
|
||||
</div>
|
||||
</Teleport>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.fms-message-container {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
z-index: var(--fms-z-message);
|
||||
/* 容器本身不拦截页面交互,仅子项可交互 */
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.fms-message-list {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
padding: var(--fms-feedback-offset);
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
/* 垂直方位(主轴):上 / 中 / 下 */
|
||||
.fms-placement-top {
|
||||
justify-content: flex-start;
|
||||
}
|
||||
.fms-placement-center-v {
|
||||
justify-content: center;
|
||||
}
|
||||
.fms-placement-bottom {
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
/* 水平方位(交叉轴):左 / 中 / 右 */
|
||||
.fms-placement-left {
|
||||
align-items: flex-start;
|
||||
}
|
||||
.fms-placement-center-h {
|
||||
align-items: center;
|
||||
}
|
||||
.fms-placement-right {
|
||||
align-items: flex-end;
|
||||
}
|
||||
|
||||
/* 入场/退场:基础淡入淡出 + 位移,方向随方位 */
|
||||
.fms-message-enter-active,
|
||||
.fms-message-leave-active {
|
||||
transition:
|
||||
opacity 0.28s ease,
|
||||
transform 0.28s cubic-bezier(0.22, 1, 0.36, 1);
|
||||
}
|
||||
|
||||
.fms-message-enter-from,
|
||||
.fms-message-leave-to {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
/* 左侧锚定:从左侧滑入、向左侧滑出 */
|
||||
.fms-placement-left .fms-message-enter-from,
|
||||
.fms-placement-left .fms-message-leave-to {
|
||||
transform: translateX(-24px);
|
||||
}
|
||||
/* 右侧锚定:从右侧滑入、向右侧滑出 */
|
||||
.fms-placement-right .fms-message-enter-from,
|
||||
.fms-placement-right .fms-message-leave-to {
|
||||
transform: translateX(24px);
|
||||
}
|
||||
/* top-center:从顶部滑入/滑出 */
|
||||
.fms-placement-top.fms-placement-center-h .fms-message-enter-from,
|
||||
.fms-placement-top.fms-placement-center-h .fms-message-leave-to {
|
||||
transform: translateY(-16px);
|
||||
}
|
||||
/* bottom-center:从底部滑入/滑出 */
|
||||
.fms-placement-bottom.fms-placement-center-h .fms-message-enter-from,
|
||||
.fms-placement-bottom.fms-placement-center-h .fms-message-leave-to {
|
||||
transform: translateY(16px);
|
||||
}
|
||||
/* center 正中央:仅淡入淡出 */
|
||||
|
||||
/* 退场时脱离文档流,便于剩余项平滑上移 */
|
||||
.fms-message-leave-active {
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.fms-message-move {
|
||||
transition: transform 0.28s cubic-bezier(0.22, 1, 0.36, 1);
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.fms-message-enter-active,
|
||||
.fms-message-leave-active,
|
||||
.fms-message-move {
|
||||
transition: none;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in new issue
Block a user