129 lines
3.3 KiB
Vue
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"></div>
|
|
<div v-else-if="msg.messageType == 'success'" class="startMessageIconFont messageSuccess">
|
|
</div>
|
|
<div v-else-if="msg.messageType == 'warning'" class="startMessageIconFont messageWarning">
|
|
</div>
|
|
<div v-else-if="msg.messageType == 'error'" class="startMessageIconFont messageError"></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> |