starwait/components/Ni/Message.vue
2025-04-27 04:17:35 +08:00

129 lines
3.3 KiB
Vue

<!-- components/MessageContainer.vue -->
<script setup>
const {messages} = useNiMessage()
</script>
<template>
<teleport to="#teleports">
<TransitionGroup name="niMessage" tag="div" class="NiMessage" data-prefix="Ni">
<div class="niMessageContent" v-for="msg in messages" :key="msg.id" @mouseenter="msg.pause()"
@mouseleave="msg.resume()">
<div class="niMessageIcon">
<div v-if="msg.messageType == 'log'" class="startMessageIconFont messageLog">
<NiLogo/>
</div>
<div v-else-if="msg.messageType == 'info'" class="startMessageIconFont messageInfo">&#xe871;</div>
<div v-else-if="msg.messageType == 'success'" class="startMessageIconFont messageSuccess">&#xe842;
</div>
<div v-else-if="msg.messageType == 'warning'" class="startMessageIconFont messageWarning">&#xe83d;
</div>
<div v-else-if="msg.messageType == 'error'" class="startMessageIconFont messageError">&#xe839;</div>
</div>
<div class="niMessageBody">
{{ msg.content }}
</div>
</div>
</TransitionGroup>
</teleport>
</template>
<style scoped lang="scss">
// 动画
.niMessage-enter-active, .niMessage-leave-active {
transition: all .5s ease-in-out;
}
.niMessage-enter-from, .niMessage-leave-to {
transform: translateY(-100%);
opacity: 0;
}
.NiMessage {
position: fixed;
top: 20px;
left: 50%;
transform: translateX(-50%);
display: flex;
flex-direction: column; /* 新消息在上方 */
gap: 10px;
z-index: 9999;
pointer-events: none; /* 容器不阻挡点击 */
}
.niMessageContent {
position: relative;
display: flex;
align-items: center;
padding: var(--Ni-content-padding);
transition: all 0.3s;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.15);
border-radius: var(--Ni-border-radius);
background: #fefefe;
cursor: pointer;
letter-spacing: 1px;
pointer-events: auto; /* 单个消息可交互 */
max-width: min(1000px, 80vw);
& > div.niMessageIcon {
position: relative;
flex-shrink: 0;
margin-right: .8rem;
& > div {
font-size: 1.6rem;
}
& > div.messageLog {
font-size: 6px;
}
& > div.messageInfo {
color: var(--Ni-button-info-bg-default);
}
& > div.messageSuccess {
color: var(--Ni-button-success-bg-default);
}
& > div.messageWarning {
color: var(--Ni-button-warning-bg-default);
}
& > div.messageError {
color: var(--Ni-button-error-bg-default);
}
}
& > div.niMessageBody {
position: relative;
display: flex;
align-items: center;
}
}
/* 入场动画 */
.nimessage-enter-active {
animation: slideIn 0.3s ease-out;
}
/* 离场动画 */
.nimessage-leave-active {
transition: opacity 0.3s ease-out;
position: absolute;
}
.nimessage-leave-to {
opacity: 0;
}
@keyframes slideIn {
from {
transform: translateY(-100%);
opacity: 0;
}
to {
transform: translateY(0);
opacity: 1;
}
}
</style>