index.vue 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. <template>
  2. <view v-if="show"
  3. :style="{width: systemInfo.width + 'px', height: systemInfo.height + 'px', backgroundColor: bgcolor, position: 'absolute', left: 0, top: 0, zIndex: 9998}">
  4. <view v-for="(item,rect_idx) in skeletonRectLists" :key="item.rect"
  5. :class="[loading == 'chiaroscuro' ? 'chiaroscuro' : '']"
  6. :style="{width: item.width + 'px', height: item.height + 'px', backgroundColor: 'rgb(194, 207, 214,.3)', position: 'absolute', left: item.left + 'px', top: item.top + 'px'}">
  7. </view>
  8. <view v-for="(item,circle_idx) in skeletonCircleLists" :key="item.circle"
  9. :class="loading == 'chiaroscuro' ? 'chiaroscuro' : ''"
  10. :style="{width: item.width + 'px', height: item.height + 'px', backgroundColor: 'rgb(194, 207, 214,.3)', borderRadius: item.width + 'px', position: 'absolute', left: item.left + 'px', top: item.top + 'px'}">
  11. </view>
  12. <view class="spinbox" v-if="loading == 'spin'">
  13. <view class="spin"></view>
  14. </view>
  15. </view>
  16. </template>
  17. <script>
  18. export default {
  19. name: "skeleton",
  20. props: {
  21. bgcolor: {
  22. type: String,
  23. value: '#FFF'
  24. },
  25. selector: {
  26. type: String,
  27. value: 'skeleton'
  28. },
  29. loading: {
  30. type: String,
  31. value: 'spin'
  32. },
  33. show: {
  34. type: Boolean,
  35. value: false
  36. },
  37. isNodes: {
  38. type: Number,
  39. value: false
  40. } //控制什么时候开始抓取元素节点,只要数值改变就重新抓取
  41. },
  42. data() {
  43. return {
  44. loadingAni: ['spin', 'chiaroscuro'],
  45. systemInfo: {},
  46. skeletonRectLists: [],
  47. skeletonCircleLists: []
  48. }
  49. },
  50. watch: {
  51. isNodes(val) {
  52. this.readyAction();
  53. }
  54. },
  55. mounted() {
  56. this.attachedAction();
  57. },
  58. methods: {
  59. attachedAction: function() {
  60. //默认的首屏宽高,防止内容闪现
  61. const systemInfo = uni.getSystemInfoSync();
  62. this.systemInfo = {
  63. width: systemInfo.windowWidth,
  64. height: systemInfo.windowHeight
  65. };
  66. this.loading = this.loadingAni.includes(this.loading) ? this.loading : 'spin';
  67. },
  68. readyAction: function() {
  69. const that = this;
  70. //绘制背景
  71. uni.createSelectorQuery().selectAll(`.${this.selector}`).boundingClientRect().exec(function(res) {
  72. if(res[0].length>0)
  73. that.systemInfo.height = res[0][0].height + res[0][0].top;
  74. });
  75. //绘制矩形
  76. this.rectHandle();
  77. //绘制圆形
  78. this.radiusHandle();
  79. },
  80. rectHandle: function() {
  81. const that = this;
  82. //绘制不带样式的节点
  83. uni.createSelectorQuery().selectAll(`.${this.selector}-rect`).boundingClientRect().exec(function(res) {
  84. let obj = res[0];
  85. obj.forEach((item,index)=>{
  86. item.rect = 'rect'+index
  87. })
  88. that.skeletonRectLists = obj;
  89. });
  90. },
  91. radiusHandle() {
  92. const that = this;
  93. uni.createSelectorQuery().selectAll(`.${this.selector}-radius`).boundingClientRect().exec(function(res) {
  94. let obj = res[0];
  95. obj.forEach((item,index)=>{
  96. item.circle = 'circle'+index
  97. })
  98. that.skeletonCircleLists = obj;
  99. });
  100. }
  101. }
  102. }
  103. </script>
  104. <style>
  105. .spinbox {
  106. position: fixed;
  107. display: flex;
  108. justify-content: center;
  109. align-items: center;
  110. height: 100%;
  111. width: 100%;
  112. z-index: 9999
  113. }
  114. .spin {
  115. display: inline-block;
  116. width: 64rpx;
  117. height: 64rpx;
  118. }
  119. .spin:after {
  120. content: " ";
  121. display: block;
  122. width: 46rpx;
  123. height: 46rpx;
  124. margin: 1rpx;
  125. border-radius: 50%;
  126. border: 5rpx solid #409eff;
  127. border-color: #409eff transparent #409eff transparent;
  128. animation: spin 1.2s linear infinite;
  129. }
  130. @keyframes spin {
  131. 0% {
  132. transform: rotate(0deg);
  133. }
  134. 100% {
  135. transform: rotate(360deg);
  136. }
  137. }
  138. .chiaroscuro {
  139. width: 100%;
  140. height: 100%;
  141. background: rgb(194, 207, 214);
  142. animation-duration: 2s;
  143. animation-name: blink;
  144. animation-iteration-count: infinite;
  145. }
  146. @keyframes blink {
  147. 0% {
  148. opacity: .4;
  149. }
  150. 50% {
  151. opacity: 1;
  152. }
  153. 100% {
  154. opacity: .4;
  155. }
  156. }
  157. @keyframes flush {
  158. 0% {
  159. left: -100%;
  160. }
  161. 50% {
  162. left: 0;
  163. }
  164. 100% {
  165. left: 100%;
  166. }
  167. }
  168. .shine {
  169. animation: flush 2s linear infinite;
  170. position: absolute;
  171. top: 0;
  172. bottom: 0;
  173. width: 100%;
  174. background: linear-gradient(to left,
  175. rgba(255, 255, 255, 0) 0%,
  176. rgba(255, 255, 255, .85) 50%,
  177. rgba(255, 255, 255, 0) 100%)
  178. }
  179. </style>