message组件
html
<template>
<transition name="fade">
<div v-if="visible" class="m-message" :class="`m-message-${type}`">
<svg v-if="type == 'success'" fill="none" viewBox="0 0 24 24" width="1em" height="1em" class="t-icon t-icon-error-circle-filled" style="fill: none">
<path
fill="currentColor"
d="M12 1C18.0751 1 23 5.92487 23 12C23 18.0751 18.0751 23 12 23C5.92487 23 1 18.0751 1 12C1 5.92487 5.92487 1 12 1ZM11.0001 14H13.0001V6.49998H11.0001V14ZM13.004 15.5H11.0001V17.5039H13.004V15.5Z"></path>
</svg>
<svg
v-else-if="type == 'error'"
fill="none"
viewBox="0 0 24 24"
width="1em"
height="1em"
class="t-icon t-icon-info-circle-filled"
style="fill: none">
<path
fill="currentColor"
d="M12 23C18.0751 23 23 18.0751 23 12C23 5.92487 18.0751 1 12 1C5.92487 1 1 5.92487 1 12C1 18.0751 5.92487 23 12 23ZM10.996 8.50002V6.49611H12.9999V8.50002H10.996ZM12.9999 10L12.9999 17.5H10.9999V10L12.9999 10Z"></path>
</svg>
<svg
v-else-if="type == 'warning'"
fill="none"
viewBox="0 0 24 24"
width="1em"
height="1em"
class="t-icon t-icon-error-circle-filled"
style="fill: none">
<path
fill="currentColor"
d="M12 1C18.0751 1 23 5.92487 23 12C23 18.0751 18.0751 23 12 23C5.92487 23 1 18.0751 1 12C1 5.92487 5.92487 1 12 1ZM11.0001 14H13.0001V6.49998H11.0001V14ZM13.004 15.5H11.0001V17.5039H13.004V15.5Z"></path>
</svg>
<svg
v-else-if="type == 'info'"
fill="none"
viewBox="0 0 24 24"
width="1em"
height="1em"
class="t-icon t-icon-info-circle-filled"
style="fill: none">
<path
fill="currentColor"
d="M12 23C18.0751 23 23 18.0751 23 12C23 5.92487 18.0751 1 12 1C5.92487 1 1 5.92487 1 12C1 18.0751 5.92487 23 12 23ZM10.996 8.50002V6.49611H12.9999V8.50002H10.996ZM12.9999 10L12.9999 17.5H10.9999V10L12.9999 10Z"></path>
</svg>
{{ text }}
</div>
</transition>
</template>
<script setup lang="ts">
import { ref, onMounted } from "vue";
const props = defineProps({
text: String,
type: {
type: String,
default: "info", // success | error | warning | info
},
duration: {
type: Number,
default: 3000,
},
});
const visible = ref(false);
onMounted(() => {
visible.value = true;
setTimeout(() => {
visible.value = false;
}, props.duration);
});
</script>
<style lang="scss" scoped>
@media screen and (min-width: 768px) {
.m-message {
display: flex;
align-items: center;
gap: 8px;
padding: 12px 16px;
width: fit-content;
height: fit-content;
background-color: #fff;
border-radius: 6px;
color: #041e39;
font-size: 14px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
opacity: 0.95;
white-space: nowrap;
& > svg {
width: 16px;
height: 16px;
}
}
}
@media screen and (max-width: 768px) {
.m-message {
display: flex;
align-items: center;
gap: 0.8rem;
padding: 1.2rem 1.6rem;
width: fit-content;
height: fit-content;
background-color: #fff;
border-radius: 0.6rem;
color: #041e39;
font-size: 1.4rem;
box-shadow: 0 0.2rem 0.8rem rgba(0, 0, 0, 0.15);
opacity: 0.95;
white-space: nowrap;
& > svg {
width: 1.6rem;
height: 1.6rem;
}
}
}
/* 不同类型的颜色 */
.m-message-success {
color: #67c23a;
}
.m-message-error {
color: #f56c6c;
}
.m-message-warning {
color: #e6a23c;
}
.m-message-info {
color: #909399;
}
/* 动画 */
.fade-enter-active,
.fade-leave-active {
transition: all 0.3s ease;
}
.fade-enter-from,
.fade-leave-to {
opacity: 0;
transform: translateY(-10px);
}
</style>
注册成方法
javascript
import { createVNode, render } from "vue";
import MessageComponent from "@/components/M/Message/index.vue";
type MessageType = "success" | "error" | "warning" | "info";
// 维护当前已显示的消息节点容器
const messageInstances: HTMLElement[] = [];
function showMessage(type: MessageType, text: string, duration = 2000) {
const container = document.createElement("div");
container.className = "custom-message-container";
document.body.appendChild(container);
const vnode = createVNode(MessageComponent, { text, type, duration });
render(vnode, container);
// 记录实例
messageInstances.push(container);
// 调整每个消息的位置(根据索引累积 20px)
updateMessagePositions();
// 定时销毁节点
setTimeout(() => {
render(null, container);
document.body.removeChild(container);
messageInstances.splice(messageInstances.indexOf(container), 1);
updateMessagePositions();
}, duration + 500);
}
// 更新所有 message 的位置
function updateMessagePositions() {
messageInstances.forEach((container, index) => {
const offset = index == 0 ? 12 : index * 62; // 每条间隔12px
container.style.position = "fixed";
container.style.top = `${offset}px`;
container.style.left = "50%";
container.style.width = "fit-content";
container.style.transform = "translateX(-50%)";
container.style.zIndex = "9999";
container.style.transition = "all 0.3s";
});
}
export const Message = {
success: (text: string, duration?: number) => showMessage("success", text, duration),
error: (text: string, duration?: number) => showMessage("error", text, duration),
warning: (text: string, duration?: number) => showMessage("warning", text, duration),
info: (text: string, duration?: number) => showMessage("info", text, duration),
};
export default Message;
使用:
javascript
import message from "@/utils/message.ts";
message.error("6666");