J-skeleton.vue 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. <template>
  2. <!-- 骨架屏-->
  3. <view>
  4. <view v-if="loading" class="skeleton" :class="{ animate: animate }" :style="{ justifyContent: flexType }">
  5. <!-- 轮播图 -->
  6. <view v-if="imgTitle" class="skeleton-imgTitle" style="width: 95%;border-radius: 10px;height: 100px;display: block;"></view>
  7. <!-- 头像图 -->
  8. <view
  9. v-if="showAvatar && !imgTitle"
  10. class="skeleton-avatar"
  11. v-for="(item, index) in nameRow"
  12. :key="index"
  13. :class="[avatarShape]"
  14. :style="{ width: avatarSize, height: avatarSize }"
  15. ></view>
  16. <!-- 文字条 -->
  17. <view class="skeleton-content" v-if="showTitle && !imgTitle">
  18. <view class="skeleton-title" :style="{ width: titleWidth }"></view>
  19. <view class="skeleton-rows"><view class="skeleton-row-item" v-for="(item, index) in rowList" :key="index" :style="{ width: item.width }"></view></view>
  20. </view>
  21. </view>
  22. <view v-else><slot></slot></view>
  23. <view class="NavBar clearfix">
  24. <view class="nav-li" v-for="(item, index) in 8" :key="index"><view class="nav-icon"></view></view>
  25. </view>
  26. <view class="magic-adv-view"></view>
  27. <view class="seckill-view">
  28. <view class="seckill-top"></view>
  29. <view class="seckill-goods-view">
  30. <view
  31. class="seckill-goods"
  32. style="margin-right: 20upx;"
  33. ></view>
  34. <view class="seckill-goods"></view>
  35. </view>
  36. </view>
  37. </view>
  38. </template>
  39. <script>
  40. const DEFAULT_ROW_WIDTH = '100%';
  41. const DEFAULT_LAST_ROW_WIDTH = '60%';
  42. export default {
  43. name: "Skeleton",
  44. props: {
  45. loading: {
  46. type: Boolean,
  47. default: true
  48. },
  49. imgTitle: {
  50. type: Boolean,
  51. default: false
  52. },
  53. nameRow: {
  54. type: Number,
  55. default: 1
  56. },
  57. flexType: {
  58. type: String,
  59. default: 'flex-start' // center 居中 √ space-between 两端对齐 √ space-around 子元素拉手分布 √ flex-start 居左 flex-end 居右
  60. },
  61. showAvatar: {
  62. type: Boolean,
  63. default: true
  64. },
  65. avatarSize: {
  66. type: String,
  67. default: '50px'
  68. },
  69. avatarShape: {
  70. type: String,
  71. default: 'round' // square | round
  72. },
  73. showTitle: {
  74. type: Boolean,
  75. default: false
  76. },
  77. titleWidth: {
  78. type: String,
  79. default: '40%'
  80. },
  81. row: {
  82. type: Number,
  83. default: 3
  84. },
  85. animate: {
  86. type: Boolean,
  87. default: true
  88. }
  89. },
  90. data() {
  91. return {};
  92. },
  93. computed: {
  94. rowList() {
  95. let list = [];
  96. for (let i = 0; i < this.row; i++) {
  97. list.push({
  98. width: i === this.row - 1 && i !== 0 ? DEFAULT_LAST_ROW_WIDTH : DEFAULT_ROW_WIDTH
  99. });
  100. }
  101. return list;
  102. }
  103. }
  104. };
  105. </script>
  106. <style scoped lang="scss">
  107. .seckill-view {
  108. width: 680upx;
  109. margin: 0 auto;
  110. .seckill-top {
  111. height: 70upx;
  112. background-color: #f5f5f5;
  113. margin-bottom: 30upx;
  114. }
  115. .seckill-goods-view {
  116. .seckill-goods {
  117. display: inline-block;
  118. width: 330upx;
  119. height: 300upx;
  120. background-color: #f5f5f5;
  121. }
  122. }
  123. }
  124. .magic-adv-view {
  125. width: 680upx;
  126. height: 200upx;
  127. background-color: #f5f5f5;
  128. margin: 20upx auto;
  129. }
  130. .NavBar {
  131. background: #fff;
  132. padding-top: 40upx;
  133. display: -webkit-flex;
  134. display: flex;
  135. width: 100%;
  136. justify-content: space-between;
  137. flex-wrap: wrap;
  138. }
  139. .nav-icon {
  140. width: 88upx;
  141. height: 88upx;
  142. margin: 0 auto;
  143. display: block;
  144. background-color: #f5f5f5;
  145. padding-bottom: 10upx;
  146. }
  147. .nav-li {
  148. width: 25%;
  149. font-size: 26upx;
  150. text-align: center;
  151. margin-bottom: 40upx;
  152. }
  153. .skeleton {
  154. display: flex;
  155. margin: 16px;
  156. --bg-color: #f2f3f5;
  157. --row-height: 16px;
  158. --row-margin-top: 16px;
  159. }
  160. .skeleton-imgTitle {
  161. flex-wrap: wrap;
  162. background: var(--bg-color);
  163. margin: 10px auto;
  164. }
  165. .skeleton-avatar {
  166. flex-shrink: 0;
  167. background: var(--bg-color);
  168. margin-right: 8px;
  169. }
  170. .skeleton-avatar.round {
  171. border-radius: 50%;
  172. }
  173. .skeleton-content {
  174. width: 100%;
  175. }
  176. .skeleton-title {
  177. background-color: var(--bg-color);
  178. height: var(--row-height);
  179. }
  180. .skeleton-title + .skeleton-rows {
  181. margin-top: var(--row-margin-top);
  182. }
  183. .skeleton-rows {
  184. }
  185. .skeleton-row-item {
  186. background-color: var(--bg-color);
  187. height: var(--row-height);
  188. }
  189. .skeleton-row-item:not(:first-child) {
  190. margin-top: var(--row-margin-top);
  191. }
  192. .skeleton.animate {
  193. animation: skeleton-blink 1.2s ease-in-out infinite;
  194. }
  195. @keyframes skeleton-blink {
  196. 0% {
  197. opacity: 1;
  198. }
  199. 50% {
  200. opacity: 0.6;
  201. }
  202. 100% {
  203. opacity: 1;
  204. }
  205. }
  206. </style>