cl-action-sheet.uvue 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. <template>
  2. <cl-popup
  3. v-model="visible"
  4. :show-close="false"
  5. :swipe-close-threshold="50"
  6. :pt="{
  7. inner: {
  8. className: parseClass([[isDark, '!bg-surface-700', '!bg-surface-100']])
  9. }
  10. }"
  11. :mask-closable="config.maskClosable"
  12. :title="config.title"
  13. >
  14. <view class="cl-action-sheet" :class="[pt.className]">
  15. <slot name="prepend"></slot>
  16. <view class="cl-action-sheet__description" v-if="config.description != ''">
  17. <text class="text-surface-400 text-md">{{ config.description }}</text>
  18. </view>
  19. <view class="cl-action-sheet__list" :class="[pt.list?.className]">
  20. <view
  21. class="cl-action-sheet__item"
  22. :class="[`${isDark ? '!bg-surface-800' : 'bg-white'}`, pt.item?.className]"
  23. v-for="(item, index) in config.list"
  24. :key="index"
  25. :hover-class="`${isDark ? '!bg-surface-900' : '!bg-surface-50'}`"
  26. :hover-stay-time="100"
  27. @tap="onItemTap(item)"
  28. >
  29. <slot name="item" :item="item">
  30. <cl-icon
  31. :name="item.icon"
  32. :pt="{
  33. className: 'mr-2'
  34. }"
  35. :color="item.color"
  36. v-if="item.icon != null"
  37. ></cl-icon>
  38. <cl-text :color="item.color">{{ item.label }}</cl-text>
  39. </slot>
  40. </view>
  41. </view>
  42. <slot name="append"></slot>
  43. </view>
  44. </cl-popup>
  45. </template>
  46. <script setup lang="ts">
  47. import { ref, reactive, computed } from "vue";
  48. import type { ClActionSheetItem, ClActionSheetOptions, PassThroughProps } from "../../types";
  49. import { t } from "@/locale";
  50. import { isDark, parseClass, parsePt } from "@/cool";
  51. defineOptions({
  52. name: "cl-action-sheet"
  53. });
  54. defineSlots<{
  55. prepend(): any;
  56. append(): any;
  57. item(props: { item: ClActionSheetItem }): any;
  58. }>();
  59. // 组件属性定义
  60. const props = defineProps({
  61. // 透传样式配置
  62. pt: {
  63. type: Object,
  64. default: () => ({})
  65. }
  66. });
  67. // 透传样式类型定义
  68. type PassThrough = {
  69. className?: string; // 根元素类名
  70. item?: PassThroughProps; // 列表项样式
  71. list?: PassThroughProps; // 列表样式
  72. };
  73. // 解析透传样式配置
  74. const pt = computed(() => parsePt<PassThrough>(props.pt));
  75. // 控制弹窗显示状态
  76. const visible = ref(false);
  77. // 操作表配置数据
  78. const config = reactive<ClActionSheetOptions>({
  79. title: "", // 标题
  80. list: [] // 操作列表
  81. });
  82. /**
  83. * 关闭操作表
  84. * 设置visible为false隐藏弹窗
  85. */
  86. function close() {
  87. visible.value = false;
  88. }
  89. /**
  90. * 打开操作表
  91. * @param options 操作表配置选项
  92. */
  93. function open(options: ClActionSheetOptions) {
  94. // 显示弹窗
  95. visible.value = true;
  96. // 更新标题
  97. config.title = options.title;
  98. // 更新描述
  99. config.description = options.description ?? "";
  100. // 更新操作列表
  101. config.list = options.list;
  102. // 取消按钮文本
  103. config.cancelText = options.cancelText ?? t("取消");
  104. // 是否显示取消按钮
  105. config.showCancel = options.showCancel ?? true;
  106. // 是否可以点击遮罩关闭
  107. config.maskClosable = options.maskClosable ?? true;
  108. // 如果需要显示取消按钮,添加到列表末尾
  109. if (config.showCancel!) {
  110. config.list.push({
  111. label: config.cancelText!,
  112. callback() {
  113. close();
  114. }
  115. } as ClActionSheetItem);
  116. }
  117. }
  118. /**
  119. * 点击列表项事件处理
  120. * @param item 被点击的操作项
  121. */
  122. function onItemTap(item: ClActionSheetItem) {
  123. // 如果存在回调函数则执行
  124. if (item.callback != null) {
  125. item.callback!();
  126. }
  127. }
  128. // 暴露组件方法供外部调用
  129. defineExpose({
  130. open,
  131. close
  132. });
  133. </script>
  134. <style scoped lang="scss">
  135. .cl-action-sheet {
  136. &__description {
  137. @apply flex flex-row items-center justify-center;
  138. margin-bottom: 30rpx;
  139. }
  140. &__list {
  141. padding: 0 20rpx;
  142. }
  143. &__item {
  144. @apply flex flex-row items-center justify-center rounded-lg;
  145. padding: 20rpx;
  146. margin-bottom: 20rpx;
  147. }
  148. }
  149. </style>