cl-radio.uvue 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. <template>
  2. <view
  3. class="cl-radio"
  4. :class="[
  5. {
  6. 'cl-radio--disabled': disabled,
  7. 'cl-radio--checked': isChecked
  8. },
  9. pt.className
  10. ]"
  11. @tap="onTap"
  12. >
  13. <cl-icon
  14. v-if="showIcon"
  15. :name="iconName"
  16. :size="pt.icon?.size ?? 40"
  17. :pt="{
  18. className: parseClass([
  19. 'cl-radio__icon mr-1',
  20. {
  21. '!text-primary-500': isChecked
  22. },
  23. pt.icon?.className
  24. ])
  25. }"
  26. ></cl-icon>
  27. <cl-text
  28. :pt="{
  29. className: parseClass([
  30. 'cl-radio__label',
  31. {
  32. '!text-primary-500': isChecked
  33. },
  34. pt.label?.className
  35. ])
  36. }"
  37. v-if="showLabel"
  38. >
  39. <slot>{{ label }}</slot>
  40. </cl-text>
  41. </view>
  42. </template>
  43. <script lang="ts" setup>
  44. import { computed, useSlots } from "vue";
  45. import type { PassThroughProps } from "../../types";
  46. import { get, parseClass, parsePt } from "@/cool";
  47. import type { ClIconProps } from "../cl-icon/props";
  48. defineOptions({
  49. name: "cl-radio"
  50. });
  51. // 定义组件属性
  52. const props = defineProps({
  53. modelValue: {
  54. type: null
  55. },
  56. // 透传样式配置
  57. pt: {
  58. type: Object,
  59. default: () => ({})
  60. },
  61. // 选中时的图标
  62. activeIcon: {
  63. type: String,
  64. default: "checkbox-circle-line"
  65. },
  66. // 未选中时的图标
  67. inactiveIcon: {
  68. type: String,
  69. default: "checkbox-blank-circle-line"
  70. },
  71. // 是否显示图标
  72. showIcon: {
  73. type: Boolean,
  74. default: true
  75. },
  76. // 标签文本
  77. label: {
  78. type: String,
  79. default: ""
  80. },
  81. // 选项值 - 该单选框对应的值
  82. value: {
  83. type: null
  84. },
  85. // 是否禁用
  86. disabled: {
  87. type: Boolean,
  88. default: false
  89. }
  90. });
  91. // 定义组件事件
  92. const emit = defineEmits(["update:modelValue", "change"]);
  93. const slots = useSlots();
  94. // 透传样式类型定义
  95. type PassThrough = {
  96. className?: string;
  97. icon?: ClIconProps;
  98. label?: PassThroughProps;
  99. };
  100. // 解析透传样式配置
  101. const pt = computed(() => parsePt<PassThrough>(props.pt));
  102. // 是否为选中状态
  103. const isChecked = computed(() => props.modelValue == props.value);
  104. // 是否显示标签
  105. const showLabel = computed(() => props.label != "" || get(slots, "default") != null);
  106. // 图标名称
  107. const iconName = computed(() => {
  108. // 选中状态
  109. if (isChecked.value) {
  110. return props.activeIcon;
  111. }
  112. // 默认状态
  113. return props.inactiveIcon;
  114. });
  115. /**
  116. * 点击事件处理函数
  117. * 在非禁用状态下切换选中状态
  118. */
  119. function onTap() {
  120. if (!props.disabled) {
  121. emit("update:modelValue", props.value);
  122. emit("change", props.value);
  123. }
  124. }
  125. </script>
  126. <style lang="scss" scoped>
  127. .cl-radio {
  128. @apply flex flex-row items-center;
  129. &--disabled {
  130. @apply opacity-70;
  131. }
  132. }
  133. </style>