Files
WAI_Project_UNIX/uni_modules/cool-ui/components/cl-action-sheet/cl-action-sheet.uvue
2025-09-03 19:03:39 +08:00

180 lines
3.7 KiB
Plaintext

<template>
<cl-popup
v-model="visible"
:show-close="false"
:swipe-close-threshold="50"
:pt="{
inner: {
className: parseClass([[isDark, '!bg-surface-700', '!bg-surface-100']])
}
}"
:mask-closable="config.maskClosable"
:title="config.title"
>
<view class="cl-action-sheet" :class="[pt.className]">
<slot name="prepend"></slot>
<view class="cl-action-sheet__description" v-if="config.description != ''">
<cl-text
:pt="{
className: '!text-surface-400 !text-md text-center'
}"
>{{ config.description }}</cl-text
>
</view>
<view class="cl-action-sheet__list" :class="[pt.list?.className]">
<view
class="cl-action-sheet__item"
:class="[`${isDark ? '!bg-surface-800' : 'bg-white'}`, pt.item?.className]"
v-for="(item, index) in config.list"
:key="index"
:hover-class="`${isDark ? '!bg-surface-900' : '!bg-surface-50'}`"
:hover-stay-time="250"
@tap="onItemTap(item)"
>
<slot name="item" :item="item">
<cl-icon
:name="item.icon"
:pt="{
className: 'mr-2'
}"
:color="item.color"
v-if="item.icon != null"
></cl-icon>
<cl-text :color="item.color">{{ item.label }}</cl-text>
</slot>
</view>
</view>
<slot name="append"></slot>
</view>
</cl-popup>
</template>
<script setup lang="ts">
import { ref, reactive, computed } from "vue";
import type { ClActionSheetItem, ClActionSheetOptions, PassThroughProps } from "../../types";
import { t } from "@/locale";
import { isDark, parseClass, parsePt } from "@/cool";
defineOptions({
name: "cl-action-sheet"
});
defineSlots<{
prepend(): any;
append(): any;
item(props: { item: ClActionSheetItem }): any;
}>();
// 组件属性定义
const props = defineProps({
// 透传样式配置
pt: {
type: Object,
default: () => ({})
}
});
// 透传样式类型定义
type PassThrough = {
className?: string; // 根元素类名
item?: PassThroughProps; // 列表项样式
list?: PassThroughProps; // 列表样式
};
// 解析透传样式配置
const pt = computed(() => parsePt<PassThrough>(props.pt));
// 控制弹窗显示状态
const visible = ref(false);
// 操作表配置数据
const config = reactive<ClActionSheetOptions>({
title: "", // 标题
list: [] // 操作列表
});
/**
* 关闭操作表
* 设置visible为false隐藏弹窗
*/
function close() {
visible.value = false;
}
/**
* 打开操作表
* @param options 操作表配置选项
*/
function open(options: ClActionSheetOptions) {
// 显示弹窗
visible.value = true;
// 更新标题
config.title = options.title;
// 更新描述
config.description = options.description ?? "";
// 更新操作列表
config.list = options.list;
// 取消按钮文本
config.cancelText = options.cancelText ?? t("取消");
// 是否显示取消按钮
config.showCancel = options.showCancel ?? true;
// 是否可以点击遮罩关闭
config.maskClosable = options.maskClosable ?? true;
// 如果需要显示取消按钮,添加到列表末尾
if (config.showCancel!) {
config.list.push({
label: config.cancelText!,
callback() {
close();
}
} as ClActionSheetItem);
}
}
/**
* 点击列表项事件处理
* @param item 被点击的操作项
*/
function onItemTap(item: ClActionSheetItem) {
// 如果存在回调函数则执行
if (item.callback != null) {
item.callback!();
}
}
// 暴露组件方法供外部调用
defineExpose({
open,
close
});
</script>
<style scoped lang="scss">
.cl-action-sheet {
&__description {
@apply flex flex-row items-center justify-center;
margin-bottom: 30rpx;
}
&__list {
padding: 0 20rpx;
}
&__item {
@apply flex flex-row items-center justify-center rounded-lg;
padding: 20rpx;
margin-bottom: 20rpx;
}
}
</style>