小元
博客
详情文字在这里缓缓展开
静候你翻开这一页

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>

       此时我们已经定义了一个基础的消息弹窗,在页面中引入并使用它后效果如图所示:

1768737708460.gif

   定义业务函数

       当我们完成基础组件的定义后,则需要创建一个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>

1768738996513.gif

       到这里就结束了,对话框和模态框也可参考此方法实现。

渝ICP备2024031078号-1
本网站一切内容不代表本站立场,并不代表本站赞同其观点和对其真实性负责。
如无意中侵犯了企业或个人的知识产权等,请及时通过电子邮件(1102905617@qq.com)告知我,本网站将会给予删除。
最新公告
😊访客你好,很高兴你的到来,本博客仍在建设中,还有些许功能尚在开发中,最后祝你在此能有所收获。
💥小元博客第三代自2025年9月上线以来,2026/08/09日迎来了它的第三次更新本次更新内容如下:
1. 文章详情页样式变更,由原来的弹窗改为单独的页面。
2. 使用Nuxt对项目进行了SEO优化,优化了搜索引擎的抓取和索引。
3. 对验签进行了优化,降低了请求被误触发拦截的概率。
4. 移动端也正在稳步推进中,在不久的将来会与大家见面。
5. 修复了首页黄历节日不显示的问题,以及其它bug的修复。