使用了Vue 3中的setup语法和TypeScript来创建一个全局的消息组件,该组件挂载在app下无需全局注册即可使用,下面是详细步骤和代码。

效果展示

0e339e1be482ae61ad86775723d604a2-image-2024013031037970

创建消息组件

首先需要创建一个名为Message.vue的Vue组件,该组件将负责显示用户的消息。

<!-- Message.vue -->
<script setup lang="ts">
  import {computed, onMounted, ref} from 'vue';

  const props = defineProps<{
    type: 'success' | 'error' | 'warning' | 'info';
    message: string;
  }>();

  const isShow = ref(false);
  const messageType = computed(() => props.type);

  onMounted(() => {
    isShow.value = true;
  });
</script>

<template>
  <Transition name="down">
    <div class="message" v-show="isShow" :class="messageType">
      <span class="text">{{ props.message }}</span>
    </div>
  </Transition>
</template>

<style scoped lang="scss">
  .message {
    margin-top: 10px;
    width: 300px;
    height: 50px;
    line-height: 50px;
    padding: 0 25px;
    border: 1px solid #e4e4e4;
    color: #fff;
    border-radius: 4px;

    i {
      margin-right: 4px;
      vertical-align: middle;
    }

    .text {
      vertical-align: middle;
    }

    &.success {
      color: #67C23A;
      background-color: #F0F9EB;
      border-color: #E1F3D8;
    }

    &.error {
      color: #F56C6C;
      background-color: #FDF6F6;
      border-color: #FDE2E2;
    }

    &.warning {
      color: #E6A23C;
      background-color: #FDF6EC;
      border-color: #FBE6C2;
    }

    &.info {
      color: #909399;
      background-color: #F4F4F5;
      border-color: #DCDFE6;
    }
  }

  .down-enter {
    &-from {
      transform: translate3d(0, -75px, 0);
      opacity: 0;
    }

    &-active {
      transition: all 0.5s;
    }

    &-to {
      transform: none;
      opacity: 1;
    }
  }
</style>

<style lang="scss">
  #gl-message {
    position: fixed;
    z-index: 9999;
    left: 50%;
    margin-left: -150px;
    top: 25px;
  }
</style>

全局消息工具函数

为了更便捷地使用消息组件,我们提供了一个Message 函数,用于动态渲染消息组件,并在一定时间后移除。此外,我们还定义了四个静态方法 success, error, warning, info ,分别用于显示不同类型的消息。

<!-- index.ts -->
import {h, render} from 'vue'
import GlMessage from './Message.vue'

type Props = {
    type: 'success' | 'error' | 'warning' | 'info'
    message: string
    duration?: number
}

export default function Message({type, message, duration = 3000}: Props) {
    // 获取或创建根元素
    const appRootElement = document.getElementById('gl-message') || createRootElement();

    // 在根元素下创建一个动态的 div 元素
    const div = document.createElement('div');
    div.setAttribute('class', 'my-message');
    appRootElement.appendChild(div);

    // 渲染消息组件
    const vNode = h(GlMessage, {type, message});
    render(vNode, div);

    // 设置定时器,在一定时间后移除消息元素
    setTimeout(() => {
        render(null, div);
        // 在定时器回调中,移除动态创建的 div 元素
        div.parentNode && div.parentNode.removeChild(div);

        // 获取所有的消息元素
        const messageElements = document.getElementsByClassName('my-message');
        // 如果没有消息元素存在,移除根元素
        if (messageElements.length === 0) {
            appRootElement.parentNode && appRootElement.parentNode.removeChild(appRootElement);
        }
    }, duration);

    // 创建或获取根元素的函数
    function createRootElement() {
        const messageElement = document.createElement('div');
        messageElement.setAttribute('id', 'gl-message');
        document.body.appendChild(messageElement);
        return messageElement;
    }
}


Message.success = (message: string, duration?: number) => {
    Message({type: 'success', message, duration})
}

Message.error = (message: string, duration?: number) => {
    Message({type: 'error', message, duration})
}

Message.warning = (message: string, duration?: number) => {
    Message({type: 'warning', message, duration})
}

Message.info = (message: string, duration?: number) => {
    Message({type: 'info', message, duration})
}

使用消息组件

无需全局注册,直接在所需的文件中引入Message函数即可使用。

<!-- App.vue -->
<script setup lang="ts">
  import Message from './components/Message/index.ts';

  Message.success('成功消息');
  Message.error('错误消息');
  Message.warning('警告消息');
  Message.info('信息消息');
</script>