You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

128 lines
2.5 KiB

5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
  1. <script setup lang="ts">
  2. import { ref } from 'vue'
  3. const props = defineProps({
  4. type: {
  5. type: String,
  6. default: 'default',
  7. },
  8. disabled: {
  9. type: Boolean,
  10. default: false,
  11. },
  12. loading: { // 添加 loading 属性
  13. type: Boolean,
  14. default: false,
  15. },
  16. onClick: {
  17. type: Function,
  18. required: false,
  19. default: () => Promise<any>,
  20. },
  21. })
  22. const isLoading = ref(false)
  23. async function handleClick() {
  24. if (!props.onClick || isLoading.value)
  25. return
  26. isLoading.value = true // 进入 loading
  27. try {
  28. await props.onClick() // 执行异步操作
  29. }
  30. finally {
  31. isLoading.value = false // 结束 loading
  32. }
  33. }
  34. const setLoading = (loading: boolean) => {
  35. isLoading.value = loading
  36. }
  37. defineExpose({
  38. setLoading,
  39. })
  40. </script>
  41. <template>
  42. <div class="ft-button" :class="{ 'ft-button-disabled': disabled || isLoading }" @click="handleClick">
  43. <!-- 添加 loading 判断 -->
  44. <div v-show="disabled || isLoading" class="my-button-shadow" /> <!-- 添加 loading 判断 -->
  45. <div
  46. class="my-button" :class="{
  47. [`my-button-${type}`]: true,
  48. 'button-disabled': disabled || isLoading, // 添加 loading 判断
  49. }"
  50. >
  51. <el-icon v-if="isLoading" :color="type === 'default' ? '#26509C' : '#fff'">
  52. <!-- 添加 loading 判断 -->
  53. <Loading class="rotate-loading" /> <!-- 添加旋转类 -->
  54. </el-icon>
  55. <slot />
  56. </div>
  57. </div>
  58. </template>
  59. <style scoped lang="scss">
  60. .ft-button {
  61. position: relative;
  62. display: inline-block;
  63. margin-right: 20px;
  64. }
  65. .ft-button-disabled {
  66. pointer-events: none;
  67. }
  68. .my-button-shadow {
  69. position: absolute;
  70. width: 100%;
  71. height: 100%;
  72. z-index: 100;
  73. }
  74. .my-button {
  75. height: var(--el-button-size);
  76. padding: 0 50px;
  77. border-radius: 10px;
  78. display: flex;
  79. align-items: center;
  80. cursor: pointer;
  81. font-size: 40px;
  82. width: fit-content;
  83. position: relative;
  84. .el-icon {
  85. position: absolute;
  86. left: 5px;
  87. svg {
  88. width: 35px;
  89. }
  90. }
  91. }
  92. .button-disabled {
  93. opacity: 0.5;
  94. }
  95. .my-button-default {
  96. background: linear-gradient(180deg, #D8E3F8 0%, #FBFCFE 100%);
  97. color: #26509C;
  98. border: 1px solid #D8E3F8;
  99. }
  100. .my-button-primary {
  101. background: linear-gradient(90deg, #0657C0 24%, #096AE0 101%);
  102. color: #fff;
  103. border: 1px solid #D8E3F8;
  104. }
  105. .my-button-info {
  106. background: #335AA5;
  107. color: #fff;
  108. border: 1px solid #335AA5;
  109. }
  110. .rotate-loading {
  111. animation: spin 1s linear infinite;
  112. }
  113. @keyframes spin {
  114. 0% { transform: rotate(0deg); }
  115. 100% { transform: rotate(360deg); }
  116. }
  117. </style>