cl-loading.uvue 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. <template>
  2. <view
  3. class="cl-loading"
  4. :class="[
  5. {
  6. 'cl-loading--dark': isDark && color == '',
  7. 'cl-loading--spin': loading,
  8. '!border-primary-500': color == 'primary',
  9. '!border-green-500': color == 'success',
  10. '!border-yellow-500': color == 'warn',
  11. '!border-red-500': color == 'error',
  12. '!border-surface-500': color == 'info',
  13. '!border-surface-700': color == 'dark',
  14. '!border-white': color == 'light',
  15. '!border-surface-300': color == 'disabled',
  16. '!border-r-transparent': true
  17. },
  18. pt.className
  19. ]"
  20. :style="{
  21. // #ifdef APP
  22. transform: `rotate(${rotate}deg)`,
  23. // #endif
  24. height: parseRpx(size!),
  25. width: parseRpx(size!),
  26. borderTopColor: color,
  27. borderRightColor: 'transparent',
  28. borderBottomColor: color,
  29. borderLeftColor: color
  30. }"
  31. v-if="loading"
  32. >
  33. </view>
  34. </template>
  35. <script setup lang="ts">
  36. import { computed, onMounted, ref, watch } from "vue";
  37. import { isDark, parsePt, parseRpx } from "@/cool";
  38. import type { ClIconProps } from "../cl-icon/props";
  39. defineOptions({
  40. name: "cl-loading"
  41. });
  42. // 定义组件属性
  43. const props = defineProps({
  44. // 透传样式
  45. pt: {
  46. type: Object,
  47. default: () => ({})
  48. },
  49. // 是否加载中
  50. loading: {
  51. type: Boolean,
  52. default: true
  53. },
  54. // 图标大小
  55. size: {
  56. type: [Number, String],
  57. default: 24
  58. },
  59. // 图标颜色
  60. color: {
  61. type: String,
  62. default: ""
  63. }
  64. });
  65. // 透传样式类型定义
  66. type PassThrough = {
  67. className?: string;
  68. icon?: ClIconProps;
  69. };
  70. // 解析透传样式
  71. const pt = computed(() => parsePt<PassThrough>(props.pt));
  72. // 旋转角度
  73. const rotate = ref(0);
  74. // 开始旋转动画
  75. function start() {
  76. requestAnimationFrame(() => {
  77. // 增加旋转角度
  78. rotate.value += 1;
  79. // 如果仍在加载中则继续旋转
  80. if (props.loading) {
  81. start();
  82. }
  83. });
  84. }
  85. // 组件挂载后监听loading状态
  86. onMounted(() => {
  87. // #ifdef APP-UVUE
  88. watch(
  89. computed(() => props.loading),
  90. (val: boolean) => {
  91. // 当loading为true时开始旋转
  92. if (val) {
  93. start();
  94. }
  95. },
  96. {
  97. immediate: true
  98. }
  99. );
  100. // #endif
  101. });
  102. </script>
  103. <style lang="scss" scoped>
  104. .cl-loading {
  105. @apply flex flex-row items-center justify-center rounded-full;
  106. @apply border-surface-700 border-solid;
  107. border-width: 2rpx;
  108. &--dark {
  109. border-color: white !important;
  110. border-right-color: transparent !important;
  111. }
  112. // #ifdef H5 || MP
  113. &--spin {
  114. animation: spin 2.5s linear infinite;
  115. }
  116. @keyframes spin {
  117. from {
  118. transform: rotate(0deg);
  119. }
  120. to {
  121. transform: rotate(360deg);
  122. }
  123. }
  124. // #endif
  125. }
  126. </style>