uniapp实现⾻架屏
前⾔:⽤户在等待数据渲染的时候,有可能因为⽹络速度慢,⼿机硬件等问题,造成等待时间延长,使得⽤户体验不好。
之前的做法是放个加载中的图标,⽽现在是直接根据页⾯原有元素绘制图形的⽅式,让⽤户有种页⾯就快渲染好的错觉。
参考资料:
备注:我是准备应⽤到项⽬中,从uniapp的插件市场下载了demo,结果出现⼀些⼩问题,在下载下来的demo做了些⼩修改
加载过程效果图:如图,从图⼀到图⼆,最底部多出了⼀个动态加载的⾻架,模拟同⼀页⾯多个数据请求(每个请求所需时间不同),
我这边的处理是在每个请求的回调中,先赋值渲染的动态数据,再重新抓取需要绘制的动态元素(因为绘制的元素需要先有数据给它撑开), 最后页⾯中的请求基本完成的时候,隐藏⾻架屏,显⽰原先的页⾯
问题:对demo有更好建议的可以提出来哈,相互学习⼀下
代码如下:
组件
1 <template>
2 <view v-if="show" :>
3 <view v-for="(item,rect_idx) in skeletonRectLists" :key="rect_idx + 'rect'" :class="[loading == 'chiaroscuro' ? 'chiaroscuro' : '']"
4 :></view>
5 <view v-for="(item,circle_idx) in skeletonCircleLists" :key="circle_idx + 'circle'" :class="loading == 'chiaroscuro' ? 'chiaroscuro' : ''"
6 :></view>
7 <view class="spinbox" v-if="loading == 'spin'">
8 <view class="spin"></view>
9 </view>
10 </view>
11 </template>
12
13 <script>
14 export default {
15 name: "skeleton",
16 props: {
17 bgcolor: {
18 type: String,
19 value: '#FFF'
20 },
21 selector: {
22 type: String,
htmlborder23 value: 'skeleton'
24 },
25 loading: {
26 type: String,
27 value: 'spin'
28 },
29 show: {
30 type: Boolean,
31 value: false
32 },
33 isNodes: {
34 type: Number,
35 value: false
36 } //控制什么时候开始抓取元素节点,只要数值改变就重新抓取
37 },
38 data() {
39return {
40 loadingAni: ['spin', 'chiaroscuro'],
41 systemInfo: {},
42 skeletonRectLists: [],
43 skeletonCircleLists: []
44 }
45 },
46 watch: {
47 isNodes (val) {
49 }
50 },
51 mounted() {
52this.attachedAction();
53 },
54 methods: {
55 attachedAction: function(){
56//默认的⾸屏宽⾼,防⽌内容闪现
57 const systemInfo = SystemInfoSync();
58this.systemInfo = {
59 width: systemInfo.windowWidth,
60 height: systemInfo.windowHeight
61 };
62this.loading = this.loadingAni.includes(this.loading) ? this.loading : 'spin';
63 },
64 readyAction: function(){
65 console.log('⼦组件readyAction')
66 const that = this;
67//绘制背景
68 ateSelectorQuery().selectAll(`.${this.selector}`).boundingClientRect().exec(function(res){
69 that.systemInfo.height = res[0][0].height + res[0][0].top;
70 });
71
72//绘制矩形
74
75//绘制圆形
76this.radiusHandle();
77 },
78 rectHandle: function(){
79 const that = this;
80
81//绘制不带样式的节点
82 ateSelectorQuery().selectAll(`.${this.selector}-rect`).boundingClientRect().exec(function(res){
83 that.skeletonRectLists = res[0];
84 });
85
86 },
87 radiusHandle(){
88 const that = this;
89
90 ateSelectorQuery().selectAll(`.${this.selector}-radius`).boundingClientRect().exec(function(res){
91 that.skeletonCircleLists = res[0];
92 });
93 }
94 }
95 }
96 </script>
97
98 <style>
99 .spinbox{
100 position: fixed;
101 display: flex;
102 justify-content: center;
103 align-items: center;
104 height: 100%;
105 width: 100%;
106 z-index: 9999
107 }
108 .spin {
109 display: inline-block;
110 width: 64rpx;
111 height: 64rpx;
112 }
113 .spin:after {
114 content: " ";
115 display: block;
116 width: 46rpx;
117 height: 46rpx;
118 margin: 1rpx;
119 border-radius: 50%;
120 border: 5rpx solid #409eff;
121 border-color: #409eff transparent #409eff transparent;
122 animation: spin 1.2s linear infinite;
123 }
124 @keyframes spin {
125 0% {
126 transform: rotate(0deg);
127 }
128 100% {
129 transform: rotate(360deg);
130 }
131 }
132
133 .chiaroscuro{
134 width: 100%;
135 height: 100%;
136 background: rgb(194, 207, 214);
137 animation-duration: 2s;
138 animation-name: blink;
139 animation-iteration-count: infinite;
140 }
141
142 @keyframes blink {
143 0% {
144 opacity: .4;
145 }
146 50% {
147 opacity: 1;
148 }
149 100% {
150 opacity: .4;
151 }
152 }
153
154 @keyframes flush {
155 0% {
156 left: -100%;
157 }
158 50% {
159 left: 0;
160 }
161 100% {
162 left: 100%;
163 }
164 }
165 .shine {
166 animation: flush 2s linear infinite;
167 position: absolute;
168 top: 0;
169 bottom: 0;
170 width: 100%;
171 background: linear-gradient(to left,
172 rgba(255, 255, 255, 0) 0%,
173 rgba(255, 255, 255, .85) 50%,
174 rgba(255, 255, 255, 0) 100%
175 )
176 }
177 </style>
View Code
页⾯demo
1 <template>
2 <view class="controller">
3 <view class="container skeleton" :>
4 <view class="userinfo">
5 <block>
6 <!--skeleton-radius 绘制圆形-->
7 <image class="userinfo-avatar skeleton-radius" :src="userInfo.avatarUrl" mode="cover"></image>
8 <!--skeleton-rect 绘制矩形-->
9 <text class="userinfo-nickname skeleton-rect">{{userInfo.nickName}}</text>
10 </block>
11 </view>
12 <view >
13 <view v-for="(item,index) in lists" :key="index" class="lists">
14 <text class="skeleton-rect">{{item}}</text>
15 </view>
16 </view>
17 <view class="usermotto">
18 <text class="user-motto skeleton-rect">{{motto}}</text>
19 </view>
20 </view>
21 <!--引⽤组件-->
22 <skeleton :show="showSkeleton" :isNodes="isNodes" ref="skeleton" loading="chiaroscuro" selector="skeleton" bgcolor="#FFF"></skeleton>
23 </view>
24 </template>
25
26 <script>
27//引⼊⾻架屏组件(以我本地地址为例,具体地址由⾃⾝引⽤位置决定)
28 import skeleton from "@/components/quick-skeleton/quick-skeleton.vue";
29 export default {
30 data() {
31return {
32 motto: '',
33 userInfo: {
34 avatarUrl: 'wx.qlogo/mmopen/vi_32/s4RzXCAQsVNliaJXtHBvdpAkeRwnK7Jhiaf9mzuVqEhZza3zSYM7tJ1xZCQE9SCoOR8qjVEjDKltw1SQnxyicWq6A/132',
35 nickName: 'jayzou'
36 },
37// lists: [
38// '第1⾏数据',
39// '第2⾏数据',
40// '第3⾏数据',
41// '第4⾏数据',
42// '第5⾏数据',
43// '第6⾏数据'
44// ],
45 lists: [], //如果没有默认数据
46 showSkeleton: true, //⾻架屏显⽰隐藏
47 isNodes: 0 //控制什么时候开始抓取元素节点,只要数值改变就重新抓取
48 };
49 },
50 components: {
51 skeleton
52 },
53 onLoad: function () {
54 const that = this;
55
56//问题:⾻架屏出现的时间段,部分已经渲染完毕,但还是得等⾻架屏隐藏才⼀起出现 57
58 setTimeout(() => {
59this.lists = [
60 '第1⾏数据',
61 '第2⾏数据',
62 '第3⾏数据',
63 '第4⾏数据',
64 '第5⾏数据',
65 '第6⾏数据'
66 ]
67 that.isNodes ++;
68 }, 182);
69
70 setTimeout(() => {
71 = 'Hello World'
72 that.isNodes ++;
73 }, 500);
74
75 setTimeout(() => {
76 that.showSkeleton = false;
77 }, 2000);
78 },
79/**
80 * 页⾯载⼊完成后调⽤⼦组件的⽅法⽣成预加载效果
81*/
82 onReady:function(){
83
84 }
85 }
86 </script>
87
88 <style>
89 .container {
90 padding: 20upx 60upx;
91 }
92/**index.wxss**/
93 .userinfo {
94 display: flex;
95 flex-direction: column;
96 align-items: center;
97 }
98 .userinfo-avatar {
99 width: 128rpx;
100 height: 128rpx;
101 margin: 20rpx;
102 border-radius: 50%;
103 }
104 .userinfo-nickname {
105 color: #aaa;
106 }
107 .usermotto {
108 margin-top: 200px;
109 }
110 .lists{
111 margin: 10px 0;
112 }
113 .list{
114 margin-right: 10px;
115 }
116 </style>
View Code
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论