Vue3+TypeScript实现message组件

Vue 3 Message 组件封装

本文将介绍如何封装一个简洁且灵活的消息提示组件,支持多种类型的消息展示、自动消失、手动关闭等功能,并且提供了一些可配置的选项,如持续时间、偏移量、关闭按钮等。该组件使用了 Vue 3 的功能,包括 TransitionrefcomputeddefinePropsdefineExpose,并且通过动态创建和销毁组件实例的方式,来实现消息提示的展示。

1. 功能需求

我们需要实现一个 Message 组件,它能够满足以下功能:

  • 消息类型:支持 successinfowarningerror 四种类型的消息,显示不同的样式。
  • 自动消失:消息提示展示一段时间后自动消失。
  • 手动关闭:提供关闭按钮,用户可以手动关闭消息。
  • 自定义配置:用户可以自定义消息内容、持续时间、偏移量、zIndex 等。
  • 支持 HTML 内容:支持将 HTML 字符串作为消息内容。

2. 组件实现

2.1 Message 组件模板
<template>
  <Transition name="message-fade" @before-leave="beforeLeave" @after-leave="emit('destroy')">
    <div v-show="visible" :id="id" :class="[n(), type && n('--' + type)]" :style="styles">
      <i class="iconfont icon-chenggong" style="font-size: 20px"></i>
      <div v-if="!dangerouslyUseHTMLString" :class="n('content')">
        <slot>{{ message }}</slot>
      </div>
      <div v-else :class="n('content')" v-html="message"></div>
      <div v-if="showClose" :class="n('closeBtn')" @click="close">
        <i class="iconfont icon-close"></i>
      </div>
    </div>
  </Transition>
</template>
  • Transition:用来控制消息组件的进出场动画。
  • v-show:用于显示或隐藏消息。
  • :class:动态绑定类名,支持根据消息类型(success、info、warning、error)来设置不同的样式。
  • v-html:支持渲染 HTML 内容。
  • 关闭按钮:点击后触发 close 方法,手动关闭消息。
2.2 Message 组件的逻辑部分
<script lang="ts" setup>
import { onMounted, onBeforeMount, ref, computed } from 'vue'
import { createNamespace } from '../utils'
import { MessageProps } from './message'

defineOptions({
  name: 'VanMessage'
})

const props = defineProps(MessageProps)
const emit = defineEmits(['destroy', 'close'])

const { n } = createNamespace('message')
const visible = ref(false)
const timerId = ref()

const styles = computed(() => ({
  top: props.offset + 'px',
  zIndex: props.zIndex
}))

const startTimer = () => {
  timerId.value = setTimeout(() => {
    visible.value = false
  }, props.duration)
}

const clearTimer = () => {
  if (timerId.value) {
    clearTimeout(timerId.value)
    timerId.value = undefined
  }
}

const close = () => visible.value = false

const beforeLeave = () => {
  emit('close')
}

onMounted(() => {
  startTimer()
  visible.value = true
})

onBeforeMount(() => {
  clearTimer()
})

defineExpose({
  visible,
  close
})
</script>
  • startTimer:在组件挂载时启动定时器,设置消息的自动消失时间。
  • clearTimer:在组件销毁前清除定时器,防止内存泄漏。
  • close:手动关闭消息,改变 visible 状态。
  • beforeLeave:在消息消失前,触发 close 事件,执行关闭操作。
2.3 样式部分
<style lang="less">
@import './message.less';
</style>

message.less 文件包含了消息提示的基本样式,包括背景颜色、文字颜色、圆角、阴影等。你可以根据自己的需求进一步修改这些样式。

3. 消息提示的全局管理

为了能够全局管理消息提示,我们通过动态创建 Message 组件的实例,并将其渲染到 DOM 中。

3.1 全局消息函数实现
import { AppContext, createVNode, render, isVNode, VNode, ComponentPublicInstance } from 'vue';
import { MessagePropsTypes, MessageParams, messageTypes, MessageFn, Message } from './message';
import { isString, isFunction } from '../utils';
import MessageContructor from './Message.vue';

let seed = 1;
const instances: VNode[] = [];
let zIndex = 2000;

const message: MessageFn & Partial<Message> = function (
  options: MessageParams = {},
  context?: AppContext | null,
) {
  if (isString(options) || isVNode(options)) {
    options = { message: options } as MessageParams;
  }
  const id = `message_${seed++}`;
  let offset = 20;
  instances.forEach(v => {
    offset += v.el?.offsetHeight + 16;
  });

  const userOnClose = options.onClose;

  const props: Partial<MessagePropsTypes> = {
    ...options,
    zIndex: zIndex++,
    id,
    offset,
    onClose: () => {
      close(id, userOnClose);
    },
  };

  const messageContent = props.message;
  const vm = createVNode(
    MessageContructor,
    props,
    isFunction(messageContent)
      ? { default: messageContent }
      : isVNode(messageContent)
      ? { default: () => messageContent }
      : null,
  );

  vm.props!.onDestroy = () => {
    render(null, container);
  };

  const container = document.createElement('div');

  render(vm, container);

  let appendTo: HTMLElement | null = document.body;

  if (isString(options.appendTo)) {
    appendTo = document.querySelector(options.appendTo);
  } else if (options.appendTo && options.appendTo instanceof Element) {
    appendTo = options.appendTo;
  }

  appendTo!.appendChild(container.firstElementChild!);
  instances.push(vm);

  return {
    close: () =>
      ((vm.component!.proxy as ComponentPublicInstance<{ visible: boolean }>).visible = false),
  };
};
  • message 函数:是消息提示的全局 API,通过它我们可以在任意地方调用 message 来显示消息。
  • 动态创建组件实例:每次调用 message,都会创建一个新的 Message 组件实例并挂载到 body 上。
  • close 方法:返回一个闭包,用来关闭相应的消息实例。
3.2 支持不同类型的消息
messageTypes.forEach(type => {
  (message as any)[type] = (options: MessageParams = {}, appContext?: AppContext | null) => {
    if (isString(options) || isVNode(options)) {
      options = { message: options } as MessageParams;
    }
    message({ ...options, type }, appContext);
  };
});
  • messageTypes:定义了四种消息类型(success, info, warning, error)。根据不同的类型,显示不同样式的消息。
3.3 关闭所有消息实例
function closeAll() {
  for (let i = instances.length - 1; i >= 0; i--) {
    const instance = instances[i].component;
    (instance?.proxy as any).close();
  }
}

message.closeAll = closeAll;
  • closeAll:方法可以关闭所有正在显示的消息实例。

4. 使用示例

在 Vue 应用中,我们可以通过以下方式来使用这个消息组件:

import message from './message';

message.success('This is a success message!');
message.error('This is an error message!', { duration: 5000 });
message.info('This is an informational message!');
message.warning('This is a warning message!', { showClose: true });

你可以根据需要传递不同的配置项(如 durationoffsetshowClose 等)来定制消息的显示效果。

5. 总结

这个封装的消息提示组件为你的 Vue 项目提供了灵活的消息弹出功能,支持不同类型的消息显示、自动关闭、手动关闭等功能。通过全局管理消息实例,我们避免了频繁的 DOM 操作,同时也保持了 Vue 组件的良好架构。如果需要扩展功能,可以继续优化此组件,加入更多的配置选项或动画效果。

使用Vue3TypeScript设计网站有诸多优势,能提升开发效率,确保代码的可维护性和类型安全,以下是相关方法和实践介绍: ### 项目搭建 搭建基于Vue3 + Vite + TypeScript的项目,前期需做好准备。环境上,Node.js版本要大于12.0.0,开发工具可选用Visual Studio Code和Google Chrome。技术选型方面,采用Vue 3.2、Vite 3.0、vue-router4、vuex4、Element Plus、Volar和git 。之后进行项目初始化 [^3]。 ### 项目实践案例 - **音乐网站**:音乐网站前端架构采用Vue3 + TypeScript技术栈,为开发者提供了一套完整的前端解决方案 [^1]。 - **博客网站**:基于Vue + TypeScript + Element搭建的简洁时尚博客网站,已完成登录、注册、文章列表、文章归档、标签、关于、点赞与评论、留言、历程、文章详情(支持代码语法高亮)、文章详情目录、移动端适配、github授权登录等功能。后续待优化或实现使用vuex - class、更多TypeScript的优化技巧以及服务器渲染SSR等内容 [^2]。 以下是一个简单的Vue3 + TypeScript组件示例: ```vue <template> <div> <h1>{{ message }}</h1> <button @click="changeMessage">Change Message</button> </div> </template> <script lang="ts"> import { defineComponent, ref } from &#39;vue&#39;; export default defineComponent({ setup() { const message = ref<string>(&#39;Hello, Vue3 + TypeScript!&#39;); const changeMessage = () => { message.value = &#39;Message has been changed!&#39;; }; return { message, changeMessage }; } }); </script> ```
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值