cl-loading.uvue 2.6 KB

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