cl-tabbar.uvue 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. <template>
  2. <cl-footer
  3. :height="height"
  4. :pt="{
  5. className: parseClass([pt.footer?.className]),
  6. content: {
  7. className: parseClass(['!p-0', pt.footerContent?.className])
  8. }
  9. }"
  10. :vt="cache.key"
  11. >
  12. <view class="cl-tabbar" :class="[pt.className]" :style="tabbarStyle">
  13. <view
  14. class="cl-tabbar__item"
  15. :class="[pt.item?.className]"
  16. v-for="item in list"
  17. :key="item.value"
  18. @tap="select(item)"
  19. >
  20. <cl-image
  21. v-if="item.icon != null && showIcon"
  22. :src="modelValue == item.value ? item.selectedIcon : item.icon"
  23. :height="pt.icon?.height ?? iconSize"
  24. :width="pt.icon?.width ?? iconSize"
  25. :pt="{
  26. className: pt.icon?.className
  27. }"
  28. ></cl-image>
  29. <cl-text
  30. v-if="item.text != null && showText"
  31. :size="pt.text?.size ?? textSize"
  32. :color="modelValue == item.value ? selectedColor : color"
  33. :pt="{
  34. className: parseClass([
  35. [item.icon != null && showIcon, 'mt-[2px]'],
  36. pt.text?.className
  37. ])
  38. }"
  39. >{{ item.text }}</cl-text
  40. >
  41. </view>
  42. </view>
  43. </cl-footer>
  44. </template>
  45. <script setup lang="ts">
  46. import { getColor, getUnit, parseClass, parsePt, useCache } from "@/.cool";
  47. import { computed, type PropType } from "vue";
  48. import type { ClTabbarItem, PassThroughProps } from "../../types";
  49. import type { ClTextProps } from "../cl-text/props";
  50. import type { ClImageProps } from "../cl-image/props";
  51. defineOptions({
  52. name: "cl-tabbar"
  53. });
  54. const props = defineProps({
  55. modelValue: {
  56. type: String,
  57. default: ""
  58. },
  59. pt: {
  60. type: Object,
  61. default: () => ({})
  62. },
  63. list: {
  64. type: Array as PropType<ClTabbarItem[]>,
  65. default: () => []
  66. },
  67. height: {
  68. type: Number,
  69. default: 60
  70. },
  71. backgroundColor: {
  72. type: String,
  73. default: null
  74. },
  75. color: {
  76. type: String,
  77. default: () => getColor("surface-400")
  78. },
  79. selectedColor: {
  80. type: String,
  81. default: () => getColor("primary-500")
  82. },
  83. iconSize: {
  84. type: Number,
  85. default: 32
  86. },
  87. textSize: {
  88. type: Number,
  89. default: 12
  90. },
  91. showIcon: {
  92. type: Boolean,
  93. default: true
  94. },
  95. showText: {
  96. type: Boolean,
  97. default: true
  98. }
  99. });
  100. const emit = defineEmits(["update:modelValue", "select"]);
  101. type PassThrough = {
  102. className?: string;
  103. item?: PassThroughProps;
  104. icon?: ClImageProps;
  105. text?: ClTextProps;
  106. footer?: PassThroughProps;
  107. footerContent?: PassThroughProps;
  108. };
  109. const pt = computed(() => parsePt<PassThrough>(props.pt));
  110. // 监听高度变化
  111. const { cache } = useCache(() => [props.height]);
  112. // 计算样式
  113. const tabbarStyle = computed(() => {
  114. return {
  115. height: getUnit(props.height),
  116. backgroundColor: props.backgroundColor
  117. };
  118. });
  119. // 选择
  120. const select = (item: ClTabbarItem) => {
  121. emit("update:modelValue", item.value);
  122. emit("select", item);
  123. };
  124. </script>
  125. <style lang="scss" scoped>
  126. .cl-tabbar {
  127. @apply flex flex-row items-center flex-1;
  128. &__item {
  129. @apply flex flex-col items-center justify-center flex-1;
  130. }
  131. }
  132. </style>