<template> <view v-if="show" :style="{width: systemInfo.width + 'px', height: systemInfo.height + 'px', backgroundColor: bgcolor, position: 'absolute', left: 0, top: 0, zIndex: 9998}"> <view v-for="(item,rect_idx) in skeletonRectLists" :key="rect_idx + 'rect'" :class="[loading == 'chiaroscuro' ? 'chiaroscuro' : '']" :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'}"> </view> <view v-for="(item,circle_idx) in skeletonCircleLists" :key="circle_idx + 'circle'" :class="loading == 'chiaroscuro' ? 'chiaroscuro' : ''" :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'}"> </view> <view class="spinbox" v-if="loading == 'spin'"> <view class="spin"></view> </view> </view> </template> <script> export default { name: "skeleton", props: { bgcolor: { type: String, value: '#FFF' }, selector: { type: String, value: 'skeleton' }, loading: { type: String, value: 'spin' }, show: { type: Boolean, value: false }, isNodes: { type: Number, value: false } //控制什么时候开始抓取元素节点,只要数值改变就重新抓取 }, data() { return { loadingAni: ['spin', 'chiaroscuro'], systemInfo: {}, skeletonRectLists: [], skeletonCircleLists: [] } }, watch: { isNodes(val) { this.readyAction(); } }, mounted() { this.attachedAction(); }, methods: { attachedAction: function() { //默认的首屏宽高,防止内容闪现 const systemInfo = uni.getSystemInfoSync(); this.systemInfo = { width: systemInfo.windowWidth, height: systemInfo.windowHeight }; this.loading = this.loadingAni.includes(this.loading) ? this.loading : 'spin'; }, readyAction: function() { const that = this; //绘制背景 uni.createSelectorQuery().selectAll(`.${this.selector}`).boundingClientRect().exec(function(res) { if(res[0].length>0) that.systemInfo.height = res[0][0].height + res[0][0].top; }); //绘制矩形 this.rectHandle(); //绘制圆形 this.radiusHandle(); }, rectHandle: function() { const that = this; //绘制不带样式的节点 uni.createSelectorQuery().selectAll(`.${this.selector}-rect`).boundingClientRect().exec(function(res) { that.skeletonRectLists = res[0]; }); }, radiusHandle() { const that = this; uni.createSelectorQuery().selectAll(`.${this.selector}-radius`).boundingClientRect().exec(function(res) { that.skeletonCircleLists = res[0]; }); } } } </script> <style> .spinbox { position: fixed; display: flex; justify-content: center; align-items: center; height: 100%; width: 100%; z-index: 9999 } .spin { display: inline-block; width: 64rpx; height: 64rpx; } .spin:after { content: " "; display: block; width: 46rpx; height: 46rpx; margin: 1rpx; border-radius: 50%; border: 5rpx solid #409eff; border-color: #409eff transparent #409eff transparent; animation: spin 1.2s linear infinite; } @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } .chiaroscuro { width: 100%; height: 100%; background: rgb(194, 207, 214); animation-duration: 2s; animation-name: blink; animation-iteration-count: infinite; } @keyframes blink { 0% { opacity: .4; } 50% { opacity: 1; } 100% { opacity: .4; } } @keyframes flush { 0% { left: -100%; } 50% { left: 0; } 100% { left: 100%; } } .shine { animation: flush 2s linear infinite; position: absolute; top: 0; bottom: 0; width: 100%; background: linear-gradient(to left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, .85) 50%, rgba(255, 255, 255, 0) 100%) } </style>