index.vue 4.5 KB

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