cl-select-trigger.uvue 3.4 KB

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