Files
WAI_Project_UNIX/uni_modules/cool-ui/components/cl-toast/cl-toast.uvue
2025-07-21 16:47:04 +08:00

173 lines
3.5 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<cl-popup
v-for="(item, id) in list"
:key="id"
:direction="item.position"
:show-mask="false"
:show-header="false"
:swipe-close="false"
:pt="{
inner: {
className: '!bg-transparent'
}
}"
keep-alive
pointer-events="none"
v-model="item.visible"
>
<view class="cl-toast-wrapper">
<view
class="cl-toast"
:class="[
{
'is-dark': isDark,
'is-open': item.isOpen
},
`cl-toast--${item.position}`
]"
>
<view class="flex flex-row justify-center">
<cl-icon
:name="item.icon"
:size="56"
:pt="{
className: `mb-1 !text-white`
}"
v-if="item.icon != null"
></cl-icon>
</view>
<text class="cl-toast__text">{{ item.message }}</text>
</view>
</view>
</cl-popup>
</template>
<script setup lang="ts">
import { reactive, ref } from "vue";
import type { ClToastOptions } from "../../types";
import { isDark, isNull } from "@/cool";
defineOptions({
name: "cl-toast"
});
// ToastItem 类型定义表示单个toast的属性
type ToastItem = {
id: number; // 唯一标识
visible: boolean; // 是否显示
isOpen: boolean; // 是否打开
icon?: string; // 可选,图标名称
image?: string; // 可选,图片地址
message: string; // 显示的文本内容
position: "top" | "center" | "bottom"; // 显示位置
duration: number; // 显示时长(毫秒)
};
// toast列表当前仅用于v-for结构实际只显示一个
const list = ref<ToastItem[]>([]);
// 用于生成唯一id
let id = 0;
// 关闭toast的方法
function close(id: number) {
const item = list.value.find((item) => item.id == id);
if (item != null) {
item.visible = false;
}
}
// 打开toast的方法传入配置信息
function open(options: ClToastOptions) {
// 创建一个新的 ToastItem 实例,包含所有配置信息
const item = reactive<ToastItem>({
id: id++,
visible: true,
isOpen: false,
icon: options.icon,
image: options.image,
duration: options.duration ?? 2000,
position: options.position ?? "center",
message: options.message
});
// 如果有icon或image强制居中显示
if (!isNull(item.icon) || !isNull(item.image)) {
item.position = "center";
}
switch (options.type) {
case "success":
item.icon = "checkbox-circle-line";
break;
case "warn":
item.icon = "error-warning-line";
break;
case "error":
item.icon = "close-circle-line";
break;
case "question":
item.icon = "question-line";
break;
case "disabled":
item.icon = "prohibited-line";
break;
case "stop":
item.icon = "indeterminate-circle-line";
break;
}
// 如果clear为true则只保留当前toast否则追加到列表
if (options.clear == true) {
list.value = [item];
} else {
list.value.push(item);
}
// 延迟打开toast避免闪烁
setTimeout(() => {
item.isOpen = true;
// 如果duration不为0则自动关闭toast
if (item.duration != 0) {
setTimeout(() => {
close(item.id); // 到时自动关闭
}, item.duration!);
}
}, 50);
}
defineExpose({
open,
close
});
</script>
<style lang="scss" scoped>
.cl-toast-wrapper {
@apply flex flex-col items-center justify-center;
padding: 50rpx 0;
}
.cl-toast {
@apply px-[32rpx] py-[24rpx] rounded-2xl;
background-color: rgba(50, 50, 50, 0.9);
max-width: 600rpx;
opacity: 0;
&__text {
@apply text-md text-center font-bold text-white;
}
&.is-open {
opacity: 1;
}
&.is-dark {
background-color: rgba(70, 70, 70, 0.9);
}
}
</style>