client-skeleton.vue 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. <template>
  2. <view class="client-skeleton" :class="[`client-skeleton--${variant}`]">
  3. <view v-if="variant === 'hero-list'" class="hero shimmer" />
  4. <view v-if="variant === 'hero-list'" class="block card">
  5. <view class="line line-lg shimmer" />
  6. <view class="line line-md shimmer" />
  7. </view>
  8. <template v-if="variant === 'list'">
  9. <view class="block card" v-for="i in rows" :key="`row-${i}`">
  10. <view class="row">
  11. <view class="thumb shimmer" />
  12. <view class="meta">
  13. <view class="line line-lg shimmer" />
  14. <view class="line line-md shimmer" />
  15. <view class="line line-sm shimmer" />
  16. </view>
  17. </view>
  18. </view>
  19. </template>
  20. <view v-if="variant === 'detail'" class="hero shimmer" />
  21. <view v-if="variant === 'detail'" class="block card">
  22. <view class="line line-xl shimmer" />
  23. <view class="line line-md shimmer" />
  24. <view class="line line-sm shimmer" />
  25. </view>
  26. </view>
  27. </template>
  28. <script setup>
  29. defineProps({
  30. variant: {
  31. type: String,
  32. default: 'list'
  33. },
  34. rows: {
  35. type: Number,
  36. default: 3
  37. }
  38. })
  39. </script>
  40. <style scoped lang="scss">
  41. .client-skeleton {
  42. width: 100%;
  43. display: block;
  44. min-width: 100%;
  45. padding: 24rpx 32rpx calc(24rpx + env(safe-area-inset-bottom, 0px));
  46. box-sizing: border-box;
  47. background: var(--c-bg, #f5f8f7);
  48. }
  49. .hero {
  50. height: 280rpx;
  51. width: 100%;
  52. border-radius: 24rpx;
  53. margin-bottom: 20rpx;
  54. background: #e8f1ed;
  55. }
  56. .block {
  57. width: 100%;
  58. margin-bottom: 16rpx;
  59. }
  60. .card {
  61. border: 1rpx solid #dcebe4;
  62. background: #fff;
  63. border-radius: 24rpx;
  64. padding: 18rpx;
  65. }
  66. .row {
  67. display: flex;
  68. gap: 16rpx;
  69. }
  70. .thumb {
  71. width: 132rpx;
  72. height: 132rpx;
  73. border-radius: 16rpx;
  74. background: #e8f1ed;
  75. flex-shrink: 0;
  76. }
  77. .meta {
  78. flex: 1;
  79. min-width: 0;
  80. }
  81. .line {
  82. height: 22rpx;
  83. border-radius: 999rpx;
  84. background: #e8f1ed;
  85. margin-bottom: 12rpx;
  86. }
  87. .line-xl {
  88. width: 78%;
  89. height: 34rpx;
  90. }
  91. .line-lg {
  92. width: 72%;
  93. }
  94. .line-md {
  95. width: 52%;
  96. }
  97. .line-sm {
  98. width: 38%;
  99. margin-bottom: 0;
  100. }
  101. .shimmer {
  102. position: relative;
  103. overflow: hidden;
  104. }
  105. .shimmer::after {
  106. content: '';
  107. position: absolute;
  108. inset: 0;
  109. transform: translateX(-100%);
  110. background: linear-gradient(90deg, rgba(255, 255, 255, 0), rgba(255, 255, 255, 0.55), rgba(255, 255, 255, 0));
  111. animation: skeleton-slide 1.15s infinite;
  112. }
  113. @keyframes skeleton-slide {
  114. 100% {
  115. transform: translateX(100%);
  116. }
  117. }
  118. </style>