preface
Skeleton screen is also an important part of optimization, if the network is not good, interface data return is relatively slow, and then render the page, the page will have a blank situation, then skeleton is undoubtedly a good solution.
Looked at the case of the plug-in market, to modify the adjustment.
plan
There are several solutions on the market
-
The UI is given a skeleton screen image for each page
-
Cons: THE UI is time-consuming
-
The front end carries on the CSS rendering according to the page stock price
-
The front end here takes time
-
Draw according to dom nodes
-
A component wrapper that can be called repeatedly
Train of thought
Wait for the HTML loading of the page to complete, obtain the DOM node information of the page, draw and display skeleton screen components, complete the interface data request, hide skeleton screen, and render the page.
So how do YOU get dom nodes?
Define a class name on each node and get the element node information.
Skeleton components
<template> <view v-if="show" :style="{ width: systemInfo.width + 'px', height: systemInfo.height + 'px', backgroundColor: bgcolor, position: 'absolute', left: 0, top: 0, zIndex: 9998, overflow: 'hidden' }" > <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: skebgcolor, 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: skebgcolor, 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: {// skeleton backcolor: {type: String, value: Selector: {type: String, value: 'skeleton'}, // whether to display loading loading: {type: String, value: 'spin'}, // Whether to display skeleton screen components show: {type: Boolean, value: false}, // Start to obtain don node information isNodes: {type: Number, value: False}, // Draw shape background skebgColor: {type: String, default: 'RGB (194, 207, 214)'}}, data() {return {loadingAni: ['spin', 'chiaroscuro'], systemInfo: {}, skeletonRectLists: [], skeletonCircleLists: [] }; }, watch: { isNodes(val) { this.readyAction(); } }, mounted() { this.attachedAction(); }, methods: {attachedAction () {// Default first screen width to prevent flash of content const systemInfo = uni.getSystemInfosync (); this.systemInfo = { width: systemInfo.windowWidth, height: systemInfo.windowHeight }; this.loading = this.loadingAni.includes(this.loading) ? this.loading : 'spin'; }, readyAction () {console.log(' child component readyAction'); const that = this; Uni.createselectorquery ().selectAll('.${this.selector} ').boundingClientRect().exec(function(res) {uni.createsElectorQuery ().selectAll('.${this.selector} ').boundingClientRect(). that.systemInfo.height = res[0][0].height + res[0][0].top; }); // Draw the rectangle this.recthandle (); // Draw the circle this.radiusHandle(); }, rectHandle () { const that = this; Uni.createselectorquery ().selectAll('.${this.selector}-rect ').boundingClientRect().exec(function(res) {uni.createsElectorQuery ().selectAll('.${this.selector}-rect '). 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: 0.4; } 50% { opacity: 1; Opacity: 0; } } @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, 0.85) 50%, RGBA (255, 255, 255, 0) 100%); } </style>Copy the code
demo
<template> <view class="controller"> <view class="container skeleton" :style="{ visibility: showSkeleton ? 'hidden' : 'visible' }"> <view class="userinfo"> <block> <! <image class=" userinfo-avatarurl ": SRC =" userinfo.avatarurl" mode="cover"></image> <! <text class="userinfo-nickname skeleton-rect">{{userinfo.nickname}}</text> </block> </view> <view style="margin: 20px 0"> <view v-for="(item, index) in lists" :key="index" class="lists"> <text class="skeleton-rect">{{ item }}</text> </view> </view> <view class="__desc skeleton-rect">123</view> <view class="__desc skeleton-rect">123</view> <view class="__desc skeleton-rect">123</view> </view> <! <skeleton :show="showSkeleton" :isNodes="isNodes" ref="skeleton" loading="chiaroscuro" selector="skeleton" bgcolor="#FFF" :skebgcolor="'rgb(194, 207, 214)'"></skeleton> </view> </template> <script> import skeleton from '@/components/skeleton.vue'; export default { data() { return { userInfo: { avatarUrl: 'http://pic.wxhand.com/dev/student_image/d4305c73c610aa4f0841243c7455c76f', nickName: 'along' }, lists: // If there is no default data showSkeleton: true, // Skeleton screen hides isNodes: 0 // Control when to start fetching element nodes, as long as the value changes to re-fetching}; }, components: { skeleton }, onLoad () { this.$nextTick(() => { this.isNodes++; }) setTimeout(() => { this.showSkeleton = false; }, 10000); }}; </script> <style> .container { padding: 20rpx 60rpx; } .userinfo { display: flex; flex-direction: column; align-items: center; margin-top: 40rpx; } .userinfo-avatar { width: 128rpx; height: 128rpx; margin: 20rpx; border-radius: 50%; } .userinfo-nickname { color: #aaa; } .usermotto { margin-top: 200px; } .lists { margin: 10px 0; } .list { margin-right: 10px; } .__desc { font-size: 24rpx; margin-top: 10rpx; } </style>Copy the code