vue3 封装涵盖移动端和PC端的消息提示框(Toast和Message)功能

涵盖移动端和PC端的消息提示框(Toast和Message)功能,包括动态调整显示位置、显示逻辑以及动画效果。


目标

  1. 移动端

    • 同一时间只显示一条消息。

    • 支持动态调整显示位置(屏幕底部或中间)。

    • 提供简洁的动画效果。

    • 消息可点击关闭。

  2. PC端

    • 最多同时显示5条消息。

    • 消息按顺序显示,超出的消息自动移除。

    • 提供关闭按钮。


1. 消息组件(Message.vue)

消息组件支持动态位置调整,并根据设备类型(移动端或PC端)调整样式。

<template>
  <div
    v-if="visible"
    class="message"
    :class="[
      isMobile ? 'message-mobile' : 'message-pc',
      positionClass,
      { 'message-fade-in': fadeIn, 'message-fade-out': fadeOut }
    ]"
    :style="{ backgroundColor: background, color: textColor }"
    @click="closeIfMobile"
  >
    <div class="message-content">
      <span>{
  
  { message }}</span>
      <button v-if="!isMobile" class="message-close" @click="close">x</button>
    </div>
  </div>
</template>

<script lang="ts" setup>
import { ref, computed, onMounted, onUnmounted } from 'vue';

const props = defineProps({
  message: {
    type: String,
    required: true,
  },
  duration: {
    type: Number,
    default: 2000,
  },
  background: {
    type: String,
    default: '#333',
  },
  textColor: {
    type: String,
    default: '#fff',
  },
  position: {
    type: String,
    default: 'bottom', // 默认显示在底部
  },
});

const visible = ref(false);
const fadeIn = ref(false);
const fadeOut = ref(false);
const isMobile = ref(window.innerWidth <= 768);

const positionClass = computed(() => {
  return `message-${props.position}`;
});

onMounted(() => {
  visible.value = true;
  setTimeout(() => {
    fadeIn.value = true;
  }, 10);

  const timer = setTimeout(() => {
    fadeOut.value = true;
    setTimeout(() => {
      visible.value = false;
    }, 300); // 等待动画完成
  }, props.duration);

  onUnmounted(() => {
    clearTimeout(timer);
  });
});

const close = () => {
  fadeOut.value = true;
  setTimeout(() => {
    visible.value = false;
  }, 300); // 等待动画完成
};

const closeIfMobile = () => {
  if (isMobile.value) {
    close();
  }
};
</script>

<style scoped>
.message {
  position: fixed;
  z-index: 1000;
  padding: 12px 16px;
  border-radius: 8px;
  font-size: 14px;
  text-align: center;
  transition: opacity 0.3s ease, transform 0.3s ease;
  opacity: 0;
  transform: translateY(20px); /* 初始状态隐藏 */
}

.message-mobile {
  width: 90%;
  max-width: 300px;
  left: 50%;
  transform: translateX(-50%);
}

.message-bottom {
  bottom: 20px;
}

.message-center {
  top: 50%;
  transform: translate(-50%, -50%);
}

.message-pc {
  top: 20px;
  right: 20px;
  margin-bottom: 10px;
}

.message-content {
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.message-close {
  background: none;
  border: none;
  color: inherit;
  font-size: 16px;
  cursor: pointer;
}

.message-fade-in {
  opacity: 1;
  transform: translateY(0);
}

.message-fade-out {
  opacity: 0;
  transform: translateY(20px);
}
</style>


2. 消息服务(message.ts)

消息服务支持移动端和PC端的逻辑,动态调整显示位置和数量。

// src/utils/message.ts
import { createVNode, render } from 'vue';
import Message from '@/components/Message.vue';

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

const messageQueue: { content: string; options: { duration?: number; background?: string; textColor?: string; position?: string } }[] = [];
let currentMessage: ReturnType<typeof setTimeout> | null = null;
const maxPCMessages = 5; // PC 端最多显示 5 条消息
const isMobile = window.innerWidth <= 768; // 是否为移动端

export function useMessage() {
  return (content: string, options: { duration?: number; background?: string; textColor?: string; position?: string } = {}) => {
    messageQueue.push({ content, options });
    displayMessages();
  };
}

function displayMessages() {
  if (isMobile) {
    // 移动端逻辑:同一时间只显示一条消息
    if (currentMessage !== null) return;

    const { content, options } = messageQueue.shift()!;
    const vnode = createVNode(Message, {
      message: content,
      duration: options.duration || 2000,
      background: options.background || '#333',
      textColor: options.textColor || '#fff',
      position: options.position || 'bottom', // 默认显示在底部
    });

    render(vnode, container);

    currentMessage = setTimeout(() => {
      render(null, container);
      currentMessage = null;
      displayMessages(); // 显示下一条消息
    }, vnode.props?.duration || 2000);
  } else {
    // PC 端逻辑:最多同时显示 5 条消息
    if (messageQueue.length > maxPCMessages) {
      messageQueue.shift(); // 如果超过 5 条,移除最早的消息
    }

    const { content, options } = messageQueue[messageQueue.length - 1]!;
    const vnode = createVNode(Message, {
      message: content,
      duration: options.duration || 2000,
      background: options.background || '#333',
      textColor: options.textColor || '#fff',
      position: options.position || 'bottom', // 默认显示在底部
    });

    render(vnode, container);
  }
}

3. 全局挂载

main.ts 中挂载消息服务,确保可以在任何组件中调用。

// src/main.ts
import { createApp } from 'vue';
import App from './App.vue';
import { useMessage } from './utils/message';

const app = createApp(App);
const message = useMessage();

app.config.globalProperties.$message = message;
app.mount('#app');

4. 在组件中使用

在任何组件中调用 $message 方法显示消息,并可以指定显示位置。

<template>
  <div>
    <button @click="showBottomMessage">显示底部消息</button>
    <button @click="showCenterMessage">显示中间消息</button>
  </div>
</template>

<script lang="ts" setup>
const showBottomMessage = () => {
  $message('这是一条底部消息', {
    duration: 2000,
    background: '#ff5722',
    textColor: '#fff',
    position: 'bottom', // 显示在底部
  });
};

const showCenterMessage = () => {
  $message('这是一条中间消息', {
    duration: 2000,
    background: '#ff5722',
    textColor: '#fff',
    position: 'center', // 显示在中间
  });
};
</script>

总结

通过上述实现,我们确保了:

  1. 移动端

    • 同一时间只显示一条消息。

    • 支持动态调整显示位置(底部或中间)。

    • 提供简洁的动画效果。

    • 消息可点击关闭。

  2. PC端

    • 最多同时显示5条消息。

    • 消息按顺序显示,超出的消息自动移除。

    • 提供关闭按钮。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值