cl-select-trigger.uvue 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. <template>
  2. <view
  3. class="cl-select-trigger"
  4. :class="[
  5. {
  6. 'is-dark': isDark,
  7. 'cl-select-trigger--disabled': disabled,
  8. 'cl-select-trigger--focus': focus
  9. },
  10. pt.className
  11. ]"
  12. >
  13. <view class="cl-select-trigger__content">
  14. <cl-text
  15. v-if="showText"
  16. :pt="{
  17. className: parseClass([
  18. {
  19. '!text-surface-400': disabled
  20. },
  21. pt.text?.className
  22. ])
  23. }"
  24. ellipsis
  25. >
  26. {{ text }}
  27. </cl-text>
  28. <text
  29. class="cl-select-trigger__placeholder"
  30. :class="[pt.placeholder?.className]"
  31. v-else
  32. >
  33. {{ placeholder }}
  34. </text>
  35. </view>
  36. <view v-if="showText && !disabled" class="cl-select-trigger__icon" @tap.stop="clear">
  37. <cl-icon
  38. name="close-circle-fill"
  39. :size="32"
  40. :pt="{ className: '!text-surface-400' }"
  41. ></cl-icon>
  42. </view>
  43. <view v-if="!disabled && !showText" class="cl-select-trigger__icon">
  44. <cl-icon
  45. :name="pt.icon?.name ?? arrowIcon"
  46. :size="pt.icon?.size ?? 32"
  47. :pt="{
  48. className: `!text-surface-400 ${pt.icon?.className}`
  49. }"
  50. ></cl-icon>
  51. </view>
  52. </view>
  53. </template>
  54. <script setup lang="ts">
  55. import { computed } from "vue";
  56. import type { ClIconProps } from "../cl-icon/props";
  57. import { isDark, parseClass, parsePt } from "@/cool";
  58. import { t } from "@/locale";
  59. import type { PassThroughProps } from "../../types";
  60. defineOptions({
  61. name: "cl-select-trigger"
  62. });
  63. // 组件属性定义
  64. const props = defineProps({
  65. // 透传样式配置
  66. pt: {
  67. type: Object,
  68. default: () => ({})
  69. },
  70. // 显示文本
  71. text: {
  72. type: String,
  73. default: ""
  74. },
  75. // 占位符文本
  76. placeholder: {
  77. type: String,
  78. default: () => t("请选择")
  79. },
  80. // 箭头图标名称
  81. arrowIcon: {
  82. type: String,
  83. default: "arrow-down-s-line"
  84. },
  85. // 是否禁用选择器
  86. disabled: {
  87. type: Boolean,
  88. default: false
  89. },
  90. // 是否聚焦
  91. focus: {
  92. type: Boolean,
  93. default: false
  94. }
  95. });
  96. const emit = defineEmits(["clear"]);
  97. // 透传样式类型定义
  98. type PassThrough = {
  99. className?: string; // 根元素类名
  100. icon?: ClIconProps; // 图标样式
  101. placeholder?: PassThroughProps; // 占位符样式
  102. text?: PassThroughProps; // 文本样式
  103. };
  104. // 解析透传样式配置
  105. const pt = computed(() => parsePt<PassThrough>(props.pt));
  106. // 是否显示文本
  107. const showText = computed(() => props.text != "");
  108. // 清空文本
  109. function clear() {
  110. emit("clear");
  111. }
  112. </script>
  113. <style lang="scss" scoped>
  114. .cl-select-trigger {
  115. @apply flex flex-row items-center w-full;
  116. @apply border border-solid border-surface-200 rounded-lg bg-white;
  117. height: 66rpx;
  118. padding: 0 20rpx;
  119. &__placeholder {
  120. @apply text-surface-400 text-md;
  121. }
  122. &__content {
  123. flex: 1;
  124. }
  125. &__icon {
  126. @apply flex flex-row items-center justify-center;
  127. padding-left: 20rpx;
  128. }
  129. &--disabled {
  130. @apply bg-surface-100 opacity-70;
  131. }
  132. &--focus {
  133. @apply border-primary-500;
  134. &.is-dark {
  135. @apply border-primary-500;
  136. }
  137. }
  138. &.is-dark {
  139. @apply border-surface-700 bg-surface-800;
  140. &.cl-select-trigger--disabled {
  141. @apply bg-surface-700;
  142. }
  143. }
  144. }
  145. </style>