文中涉及的其他组件(SIcon)可在专栏中查询
import { Message } from '@/components'
Message.success("Login successful!")
Message.success("Login successful!",3000) //第二个参数是停留时间 可选
// 消息样式
type MessageStyle = {
icon: string;
color: string;
backgroundColor: string;
borderColor: string;
};
type MessageStyleKeys = "info" | "success" | "warn" | "error"; // 支持的类型
export interface IMessageStyle {
[index in MessageStyleKeys]: MessageStyle;
[index: string]: MessageStyle;
}
// 停留时间
export const MESSAGE_TIMEOUT: number = 3000;
// message样式
// 这里的icon是自己在iconfont找的,名称与其对应,详细可参考本专栏的“Icon图标组件”文章
export const MESSAGE_STYLE: IMessageStyle = {
warn: {
icon: "icon-warn-fill",
color: "#E6A23C",
backgroundColor: "#fff7e6",
borderColor: "#ffe7ba",
},
error: {
icon: "icon-error-fill",
color: "#F56C6C",
backgroundColor: "#fff1f0",
borderColor: "#ffccc7",
},
success: {
icon: "icon-success-fill",
color: "#67C23A",
backgroundColor: "#f6ffed",
borderColor: "#d9f7be",
},
info: {
icon: "icon-info-fill",
color: "#40a9ff",
backgroundColor: "#e6f7ff",
borderColor: "#bae7ff",
},
};
消息组件:SMessage/SMessage.vue
<template>
<--!自定义动画-->
<transition name="fade">
<div class="s-message" :style="MESSAGE_STYLE[props.type]" v-if="isShow">
<s-icon :icon="MESSAGE_STYLE[props.type].icon" />
<span class="text">{{ props.text }}span>
div>
transition >
template>
<script lang="ts" setup>
import { MESSAGE_TIMEOUT, MESSAGE_STYLE } from "@/utils" // 参见上面的常量
import { SIcon } from "@/components"
import { ref, onMounted } from "vue"
const props = defineProps({
// 消息文本
text: {
type: String,
default: ""
},
// 消息类型: "info" | "success" | "warn" | "error"
type: {
type: String,
default: "warn"
},
// 消息停留时间
timeout: {
type: Number,
default: MESSAGE_TIMEOUT
}
})
// 组件状态
const isShow = ref<boolean>(false)
// 注册定时器控制组件的消失
onMounted(() => {
isShow.value = true
setTimeout(() => {
isShow.value = false
}, props.timeout)
})
script>
<style scoped lang="less">
.fade-enter-active{
animation: fade .5s;
}
.fade-leave-active {
animation: fade .5s reverse;
}
/* 定义帧动画 */
@keyframes fade {
0% {
opacity: 0;
transform: translateY(-50px);
}
100% {
opacity: 1;
}
}
.s-message {
min-width: 300px;
max-width: 350px;
padding: 8px @itemSpace;
position: fixed;
z-index: 9999;
left: 50%;
margin-left: -150px;
top: 25px;
border-radius: 4px;
.text {
vertical-align: middle;
}
}
style>
调用后挂载消息组件:SMessage/index.ts
import { MESSAGE_TIMEOUT } from "@/utils"
import { createVNode, render } from 'vue'
import SMessage from './SMessage.vue'
const div = document.createElement('div')
// 添加到body上
document.body.appendChild(div)
// 定时器标识
let timer: any = null
const renderMessage = (vnode: any, timeout: number) => {
render(null, div);// 清空上一个虚拟dom
render(vnode, div);
clearTimeout(timer);// 清理上一个定时器
timer = setTimeout(() => {
render(null, div);
}, timeout);
};
// 根据不同的调用创建虚拟dom
export default {
error: (text: string, timeout: number = MESSAGE_TIMEOUT) => {
const vnode = createVNode(SMessage, { type: "error", text, timeout });
renderMessage(vnode, timeout);
},
warn: (text: string, timeout: number = MESSAGE_TIMEOUT) => {
const vnode = createVNode(SMessage, { type: "warn", text, timeout });
renderMessage(vnode, timeout);
},
success: (text: string, timeout: number = MESSAGE_TIMEOUT) => {
const vnode = createVNode(SMessage, { type: "success", text, timeout });
renderMessage(vnode, timeout);
},
info: (text: string, timeout: number = MESSAGE_TIMEOUT) => {
const vnode = createVNode(SMessage, { type: "info", text, timeout });
renderMessage(vnode, timeout);
},
};