vite 封装一个指令式消息提示框
基于Vite + Ts 封装一个指令式消息提示框,对话框也可参考此逻辑实现。
前言:
不管什么类型的项目,消息弹窗是绕不开的地方,大多时候都需要根据UI的定制弹窗去实现样式,对于某些复杂的弹窗第三方UI库自带的弹窗就无法满足我们的需求,通常我们都是自定义封装一个弹窗组件,但在使用时,还是要写一些不必要的标签,此时如果我们将它封装成AntDesign中的Message或者小程序自带的ShowTost就完美了。
实现思路:
我们需要先封装一个.vue的基础弹窗组件,用于定义样式和显示内容,然后需要一个.ts的文件用于引入基础组件和使用“createVNode” 和 "render" 创建虚拟DOM和渲染组件,最后需要一个默认导出的index.ts文件用于导出组件。
封装基础组件
在components下创建一个Message目录,并在该目录下新建一个Message.vue的文件。
<template>
<div class="message-wrap">
<slot></slot>
</div>
</template>
<script setup lang="ts">
</script>
<style scoped>
@keyframes show {
0% {
transform: translateY(0) translateX(-50%);
}
100% {
transform: translateY(-50px) translateX(-50%);
}
}
.message-wrap {
position: fixed;
top: 100px;
left: 50%;
transform: translateX(-50%);
animation: show .5s forwards;
box-sizing: border-box;
max-width: 500px;
padding: 3px 6px;
border-radius: 4px;
background: rgba(0, 0, 0, .5);
backdrop-filter: blur(5px);
box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);
color: white;
}
</style>此时我们已经定义了一个基础的消息弹窗,在页面中引入并使用它后效果如图所示:

定义业务函数
当我们完成基础组件的定义后,则需要创建一个message.ts的文件用于编写存放业务逻辑,这里也是我们实现指令式的核心步骤。
// message.ts
import {createVNode, render, type VNode} from 'vue'
import Message from './Message.vue'
// 在根节点处创建并插入一个用于显示弹窗的容器
const messageContainer = document.createElement('div')
messageContainer.className = 'message-container'
document.body.appendChild(messageContainer)
// 用于生成唯一ID
let id = 0
export const message = (propsStr: string | VNode) => {
// 生成唯一标识
const currentId = id++
// 创建虚拟DOM,引入基础组件,并传入参数
const vnode = createVNode(Message, null, {
default: () => propsStr
})
// 创建一个DIV节点,用于挂载基础组件和设置层级
const container = document.createElement('div')
// 设置ID和层级,层级依次递增防止多个弹窗时最新的消息被遮挡住
container.setAttribute('data-message-id', currentId.toString())
container.style.zIndex = `${99 + currentId}`;
messageContainer.appendChild(container)
// 渲染组件
render(vnode, container)
// 3秒后自动销毁组件
setTimeout(() => {
render(null, container)
messageContainer.removeChild(container)
}, 1500)
}完成上述内容后,此时还不能直接使用,还缺少关键的一步在index.ts中将它导出去
// index.ts
import { message } from './message.ts'
export {
message
}测试:
在App.vue或其它页面中引入测试,此时我们便可以自定义图标或是样式和内容等,效果见代码下方。
<template>
<div>
<button style="margin-right: 6px" @click="handleOpenToast">测试自定义消息</button>
<button @click="handleOpenCustom">测试自定义内容</button>
</div>
</template>
<script setup lang="ts">
import { message } from './components/Message';
import {h} from "vue";
let i = 1;
function handleOpenToast() {
message('这是一条自定义消息' + i);
i += 1;
}
function handleOpenCustom() {
message(h('div', {
style: {
color: 'red',
fontWeight: 'bold',
fontSize: '18px',
}
}, '这是一个自定义样式'))
}
</script>
到这里就结束了,对话框和模态框也可参考此方法实现。

