176 lines
3.5 KiB
Plaintext
176 lines
3.5 KiB
Plaintext
|
|
<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
|
|||
|
|
color="white"
|
|||
|
|
:name="item.icon"
|
|||
|
|
:size="56"
|
|||
|
|
:pt="{
|
|||
|
|
className: `mb-1`
|
|||
|
|
}"
|
|||
|
|
v-if="item.icon != null"
|
|||
|
|
></cl-icon>
|
|||
|
|
</view>
|
|||
|
|
|
|||
|
|
<cl-text
|
|||
|
|
color="white"
|
|||
|
|
:pt="{
|
|||
|
|
className: 'text-center'
|
|||
|
|
}"
|
|||
|
|
>{{ item.message }}</cl-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;
|
|||
|
|
|
|||
|
|
&.is-open {
|
|||
|
|
opacity: 1;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
&.is-dark {
|
|||
|
|
background-color: rgba(70, 70, 70, 0.9);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
</style>
|