因项目需求需要一个弹框提示,之前是使用elemne-plus,但是因为项目调整不使用第三方ui库了,所以简单实现下element-plus的elMessage(ps:只做了单弹框提示,并没有做多个。动画也没有~,感兴趣的小伙伴可以自己添加哦)
message.vue
<!-- 目前的 message 只支持全局只有一个,暂时不修改为多个 -->
<template>
<div v-show="visible" class="redcat-message left" @mouseover="clear" @mouseout="startTimer">
<svgIcon :name="style.icon" :color="style.style.color" size="6px" @click="close"></svgIcon>
<span class="message-text">{{ message }}</span>
</div>
</template>
<script lang="ts" setup>
import svgIcon from '@/globComponents/svg-icon.vue'
import { getStyle, MessageProps, MessageType } from '@/utils/Message/useMessage'
import { computed, Ref, ref } from 'vue'
const message = ref('')
const type: Ref<MessageType> = ref('success')
const visible = ref(false)
const closeTime: Ref<Nullable<NodeJS.Timeout>> = ref(null)
const close = (): void => {
visible.value = false
closeTime.value && clearTimeout(closeTime.value)
closeTime.value = null
}
// 暂时定为三秒后消失
const startTimer = (): void => {
closeTime.value = setTimeout(() => {
close()
}, 3000)
}
const open = (props: MessageProps): void => {
if (closeTime.value) {
clearTimeout(closeTime.value)
}
message.value = props.message
type.value = props.type
visible.value = true
startTimer()
}
const zIndex = ref(new Date().getFullYear())
const style = computed(() => getStyle(type.value))
const clear = () => {
closeTime.value && clearTimeout(closeTime.value)
}
defineExpose({
open,
close
})
</script>
<style lang="scss" scoped>
.redcat-message {
min-width: 100%;
padding: 15px 15px 15px 20px;
border-radius: 5px;
background-color: v-bind('style.style.background');
border: v-bind('style.style.border');
color: v-bind('style.style.color');
pointer-events: all;
line-height: 1;
.svg-icon {
margin-right: 10px;
cursor: pointer;
}
}
</style>
useMessage.ts
import MessageVue from '@/utils/Message/index.vue'
import { h, render, VNode } from 'vue'
export type MessageProps = {
message: string
type: MessageType
}
type MessageFnc = (message: string) => void
type MessageProp = ((message: string | MessageProps) => void) & {
success: MessageFnc
warning: MessageFnc
info: MessageFnc
error: MessageFnc
}
export type MessageType = 'success' | 'warning' | 'info' | 'error'
export const getStyle = (type: MessageType): {
style: {
background: string
border: string
color: string
},
icon: string
} => {
// TODO 目前只有一个图标
const icon = 'delete-report'
// success
const style = {
background: '#f0f9eb',
borderColor: '#e1f3d8',
color: '#67C23B'
}
if (type === 'error') {
style.background = '#fef0f0'
style.borderColor = '#fde2e2'
style.color = '#f56c6c'
}
if (type === 'info') {
style.background = '#f4f4f5'
style.borderColor = '#e9e9eb'
style.color = '#909399'
}
if (type === 'warning') {
style.background = '#fdf6ec'
style.borderColor = '#faecd8'
style.color = '#e6a23c'
}
return {
style: {
background: style.background,
border: `1px solid ${ style.borderColor }`,
color: style.color
},
icon
}
}
const messageBoxId = 'MESSAGE-ID'
const renderMessage = (): VNode => {
const props: MessageProps = {
message: '',
type: 'success'
}
const container = document.createElement('div')
container.id = messageBoxId
Object.assign(container.style, {
minWidth: '380px',
top: '36px',
position: 'fixed',
left: 'calc(50% - 190px)',
zIndex: new Date().getFullYear(),
boxSizing: 'border-box',
fontSize: '14px',
pointerEvents: 'none'
})
// 创建 虚拟dom
const messageVNode = h(MessageVue, props)
// 将虚拟dom渲染到 container dom 上
render(messageVNode, container)
// 最后将 container 追加到 body 上
document.body.appendChild(container)
return messageVNode
}
let messageInstance: UndefinedAble<VNode>
const sendMessage = (message: string, type: MessageType): void => {
if (messageInstance) {
const messageVue = messageInstance.component
messageVue?.exposed?.open?.({ message, type })
} else {
messageInstance = renderMessage()
sendMessage(message, type)
}
}
const _Message = (message: string | MessageProps): void => {
if (typeof message === 'string') {
sendMessage(message, 'success')
} else {
sendMessage(message.message, message.type)
}
}
_Message.success = (message: string) => sendMessage(message, 'success')
_Message.warning = (message: string) => sendMessage(message, 'warning')
_Message.info = (message: string) => sendMessage(message, 'info')
_Message.error = (message: string) => sendMessage(message, 'error')
const Message: MessageProp = _Message
export default Message
使用
<template>
<div></div>
</template>
<script lang="ts" setup>
import useMessage from '@/utils/Message/useMessage'
useMessage('成功提示')
</script>
错误提示:
useMessage.error('错误提示')
// 也支持
useMessage({
message: '错误消息',
type: 'error'
})
还有其他提示我就不一一使用啦~