cl-select-trigger.uvue 3.4 KB

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