skeleton.vue 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. <template>
  2. <view>
  3. <view class="lx-skeleton" v-show="loading" :class="[avatarClass,animationClass]">
  4. <view class="avatar-class" :style="{width:avatarSize,height:avatarSize}" :class="[avatarShapeClass,bannerClass]"></view>
  5. <view class="row" :style="{width:rowWidth}">
  6. <view v-if="title" class="row-class lx-skeleton_title"></view>
  7. <view v-for="(item,index) in row" :key="item" class="row-class"></view>
  8. </view>
  9. </view>
  10. <slot v-if="!loading"></slot>
  11. </view>
  12. </template>
  13. <script>
  14. /**
  15. * skeleton 骨架屏
  16. * @description 用于加载数据时占位图显示,跟Vant-UI用法相似,但比Vant-UI更灵活
  17. * @property {Boolean} loading 是否显示骨架屏,默认为true
  18. * @property {Number | String} row 段落行数,默认为3
  19. * @property {Boolean | Number} rowWidth 段落行宽度,默认为100%
  20. * @property {Boolean | String} title 是否显示标题,默认为false
  21. * @property {Boolean | String} banner 是否显示banner,默认为false
  22. * @property {Boolean | String} animate 是否开启动画,默认为false
  23. * @property {Boolean | String} avatar 头像位置
  24. * @property {String} avatarSize 头像大小
  25. * @property {String} avatarShape 头像形状,默认为circle
  26. *
  27. * */
  28. export default {
  29. props: {
  30. loading: {
  31. type: Boolean,
  32. default: true
  33. },
  34. row: {
  35. type: Number | String,
  36. default: 3
  37. },
  38. title: {
  39. type: Boolean | Number,
  40. default: false
  41. },
  42. avatar: {
  43. type: String,
  44. default: ''
  45. },
  46. animate: {
  47. type: Boolean,
  48. default: false
  49. },
  50. avatarSize: {
  51. type: String,
  52. },
  53. rowWidth: {
  54. type: String | Number,
  55. default: '100%'
  56. },
  57. avatarShape: {
  58. type: String,
  59. default: 'circle'
  60. },
  61. banner: {
  62. type: Boolean | String,
  63. default: false
  64. },
  65. // avator-size:{
  66. // type: String,
  67. // defualt: '32px'
  68. // }
  69. },
  70. computed: {
  71. avatarClass() {
  72. if (this.avatar == 'top') {
  73. return ['lx-skeleton_avator__top']
  74. } else if (this.avatar == 'left') {
  75. return ['lx-skeleton_avator__left']
  76. } else {
  77. return ''
  78. }
  79. },
  80. animationClass() {
  81. return [this.animate ? 'lx-skeleton_animation' : '']
  82. },
  83. slotClass() {
  84. return [!this.loading ? 'show' : 'hide']
  85. },
  86. avatarShapeClass() {
  87. return [this.avatarShape == 'round' ? 'lx-skeleton_avator__round' : '']
  88. },
  89. bannerClass() {
  90. return [this.banner ? 'lx-skeleton_banner' : '']
  91. }
  92. },
  93. data() {
  94. return {
  95. }
  96. }
  97. }
  98. </script>
  99. <style lang="scss" scoped>
  100. .lx-skeleton {
  101. background-color: #fff;
  102. padding: 12px;
  103. }
  104. .lx-skeleton_avator__left {
  105. display: flex;
  106. width: 100%;
  107. }
  108. .avatar-class {
  109. }
  110. .lx-skeleton_avator__left .avatar-class,
  111. .lx-skeleton_avator__top .avatar-class {
  112. background-color: #f2f3f5;
  113. border-radius: 50%;
  114. width: 32px;
  115. height: 32px;
  116. }
  117. .lx-skeleton_avator__left .avatar-class.lx-skeleton_avator__round,
  118. .lx-skeleton_avator__top .avatar-class.lx-skeleton_avator__round {
  119. border-radius: 0;
  120. width: 32px;
  121. height: 32px;
  122. }
  123. .lx-skeleton_avator__left .avatar-class {
  124. margin-right: 16px;
  125. }
  126. .lx-skeleton_avator__top .avatar-class {
  127. margin: 0 auto 12px auto;
  128. }
  129. .row-class {
  130. width: 100%;
  131. height: 16px;
  132. background-color: #f2f3f5;
  133. }
  134. .row-class:not(:first-child) {
  135. margin-top: 12px;
  136. }
  137. .row {
  138. flex: 1;
  139. }
  140. .lx-skeleton_avator__left .row {
  141. width: calc(100% - 48px);
  142. }
  143. .row-class:nth-last-child(1) {
  144. width: 60%;
  145. }
  146. .lx-skeleton_animation .row-class {
  147. animation-duration: 1.5s;
  148. animation-name: blink;
  149. animation-timing-function: ease-in-out;
  150. animation-iteration-count: infinite;
  151. }
  152. @keyframes blink {
  153. 50% {
  154. opacity: 0.6;
  155. }
  156. }
  157. .lx-skeleton_title {
  158. width: 40%;
  159. }
  160. .show {
  161. display: block;
  162. }
  163. .hide {
  164. display: none;
  165. }
  166. .lx-skeleton .lx-skeleton_banner {
  167. width: 92%;
  168. margin: 10px auto;
  169. height: 64px;
  170. border-radius: 0;
  171. background-color: #f2f3f5;
  172. }
  173. </style>