cl-progress.uvue 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. <template>
  2. <view class="cl-progress" :class="[pt.className]">
  3. <view
  4. class="cl-progress__outer"
  5. :class="[
  6. {
  7. '!bg-surface-700': isDark && props.unColor == null
  8. },
  9. pt.outer?.className
  10. ]"
  11. :style="outerStyle"
  12. >
  13. <view
  14. class="cl-progress__inner"
  15. :class="[pt.inner?.className]"
  16. :style="innerStyle"
  17. ></view>
  18. </view>
  19. <slot name="text">
  20. <cl-rolling-number
  21. :value="value"
  22. :pt="{
  23. className: parseClass(['w-[100rpx] text-center', pt.text?.className])
  24. }"
  25. unit="%"
  26. v-if="showText"
  27. >
  28. </cl-rolling-number>
  29. </slot>
  30. </view>
  31. </template>
  32. <script lang="ts" setup>
  33. import { computed, getCurrentInstance, onMounted, ref, watch } from "vue";
  34. import { isDark, parseClass, parsePt, parseRpx } from "@/cool";
  35. import type { PassThroughProps } from "../../types";
  36. defineOptions({
  37. name: "cl-progress"
  38. });
  39. const props = defineProps({
  40. // 透传样式配置
  41. pt: {
  42. type: Object,
  43. default: () => ({})
  44. },
  45. // 数值
  46. value: {
  47. type: Number,
  48. default: 0
  49. },
  50. // 线条宽度
  51. strokeWidth: {
  52. type: Number,
  53. default: 12
  54. },
  55. // 是否显示文本
  56. showText: {
  57. type: Boolean,
  58. default: true
  59. },
  60. // 线条颜色
  61. color: {
  62. type: String,
  63. default: null
  64. },
  65. // 底色
  66. unColor: {
  67. type: String,
  68. default: null
  69. }
  70. });
  71. const { proxy } = getCurrentInstance()!;
  72. // 透传样式类型定义
  73. type PassThrough = {
  74. className?: string;
  75. outer?: PassThroughProps;
  76. inner?: PassThroughProps;
  77. text?: PassThroughProps;
  78. };
  79. // 解析透传样式配置
  80. const pt = computed(() => parsePt<PassThrough>(props.pt));
  81. // 当前值
  82. const value = ref(0);
  83. // 进度条宽度
  84. const width = ref(0);
  85. // 外层样式
  86. const outerStyle = computed(() => {
  87. const style = {};
  88. style["height"] = parseRpx(props.strokeWidth);
  89. if (props.unColor != null) {
  90. style["backgroundColor"] = props.unColor!;
  91. }
  92. return style;
  93. });
  94. // 内层样式
  95. const innerStyle = computed(() => {
  96. const style = {};
  97. style["width"] = `${(value.value / 100) * width.value}px`;
  98. if (props.color != null) {
  99. style["backgroundColor"] = props.color!;
  100. }
  101. return style;
  102. });
  103. // 获取进度条宽度
  104. function getWidth() {
  105. uni.createSelectorQuery()
  106. .in(proxy)
  107. .select(".cl-progress__outer")
  108. .boundingClientRect((node) => {
  109. width.value = (node as NodeInfo).width ?? 0;
  110. })
  111. .exec();
  112. }
  113. onMounted(() => {
  114. watch(
  115. computed(() => props.value),
  116. (val: number) => {
  117. getWidth();
  118. setTimeout(() => {
  119. if (val > 100) {
  120. value.value = 100;
  121. } else if (val < 0) {
  122. value.value = 0;
  123. } else {
  124. value.value = val;
  125. }
  126. }, 10);
  127. },
  128. {
  129. immediate: true
  130. }
  131. );
  132. });
  133. </script>
  134. <style lang="scss" scoped>
  135. .cl-progress {
  136. @apply flex flex-row items-center w-full rounded-md;
  137. &__outer {
  138. @apply bg-surface-100 relative rounded-md;
  139. flex: 1;
  140. }
  141. &__inner {
  142. @apply h-full absolute top-0 left-0 z-10 rounded-md;
  143. @apply bg-primary-500;
  144. transition-property: width;
  145. transition-duration: 0.5s;
  146. }
  147. }
  148. </style>