blob: c8cb19eb46a1aade33cd8a92663de63c6c492719 [file] [log] [blame]
guangchao.xu070005a2020-12-07 09:56:40 +08001<template>
2 <view v-if="loading" :style="{
3 width: windowWinth + 'px',
4 height: windowHeight + 'px',
5 backgroundColor: bgColor,
6 position: 'absolute',
7 left: left + 'px',
8 top: top + 'px',
9 zIndex: 9998,
10 overflow: 'hidden'
11 }"
12 @touchmove.stop.prevent>
13 <view v-for="(item, index) in RectNodes" :key="$u.guid()" :class="[animation ? 'skeleton-fade' : '']" :style="{
14 width: item.width + 'px',
15 height: item.height + 'px',
16 backgroundColor: elColor,
17 position: 'absolute',
18 left: (item.left - left) + 'px',
19 top: (item.top - top) + 'px'
20 }"></view>
21 <view v-for="(item, index) in circleNodes" :key="$u.guid()" :class="animation ? 'skeleton-fade' : ''" :style="{
22 width: item.width + 'px',
23 height: item.height + 'px',
24 backgroundColor: elColor,
25 borderRadius: item.width/2 + 'px',
26 position: 'absolute',
27 left: (item.left - left) + 'px',
28 top: (item.top - top) + 'px'
29 }"></view>
30 <view v-for="(item, index) in filletNodes" :key="$u.guid()" :class="animation ? 'skeleton-fade' : ''" :style="{
31 width: item.width + 'px',
32 height: item.height + 'px',
33 backgroundColor: elColor,
34 borderRadius: borderRadius + 'rpx',
35 position: 'absolute',
36 left: (item.left - left) + 'px',
37 top: (item.top - top) + 'px'
38 }"></view>
39 </view>
40</template>
41
42<script>
43 /**
44 * skeleton 骨架屏
45 * @description 骨架屏一般用于页面在请求远程数据尚未完成时,页面用灰色块预显示本来的页面结构,给用户更好的体验。
46 * @tutorial https://www.uviewui.com/components/skeleton.html
47 * @property {String} el-color 骨架块状元素的背景颜色(默认#e5e5e5)
48 * @property {String} bg-color 骨架组件背景颜色(默认#ffffff)
49 * @property {Boolean} animation 骨架块是否显示动画效果(默认false)
50 * @property {String Number} border-radius u-skeleton-fillet类名元素,对应的骨架块的圆角大小,单位rpx(默认10)
51 * @property {Boolean} loading 是否显示骨架组件,请求完成后,将此值设置为false(默认true)
52 * @example <u-skeleton :loading="true" :animation="true"></u-skeleton>
53 */
54 export default {
55 name: "u-skeleton",
56 props: {
57 // 需要渲染的元素背景颜色,十六进制或者rgb等都可以
58 elColor: {
59 type: String,
60 default: '#e5e5e5'
61 },
62 // 整个骨架屏页面的背景颜色
63 bgColor: {
64 type: String,
65 default: '#ffffff'
66 },
67 // 是否显示加载动画
68 animation: {
69 type: Boolean,
70 default: false
71 },
72 // 圆角值,只对类名为u-skeleton-fillet的元素生效,为数值,不带单位
73 borderRadius: {
74 type: [String, Number],
75 default: "10"
76 },
77 // 是否显示骨架,true-显示,false-隐藏
78 loading: {
79 type: Boolean,
80 default: true
81 }
82 },
83 data() {
84 return {
85 windowWinth: 750, // 骨架屏宽度
86 windowHeight: 1500, // 骨架屏高度
87 filletNodes: [], // 圆角元素
88 circleNodes: [], // 圆形元素
89 RectNodes: [], // 矩形元素
90 top: 0,
91 left: 0,
92 }
93 },
94 methods: {
95 // 查询各节点的信息
96 selecterQueryInfo() {
97 // 获取整个父组件容器的高度,当做骨架屏的高度
98 // 在微信小程序中,如果把骨架屏放入组件中使用的话,需要调in(this)上下文为父组件才有效
99 let query = '';
100 // #ifdef MP-WEIXIN
101 query = uni.createSelectorQuery().in(this.$parent);
102 // #endif
103 // #ifndef MP-WEIXIN
104 query = uni.createSelectorQuery()
105 // #endif
106 query.selectAll('.u-skeleton').boundingClientRect().exec((res) => {
107 this.windowHeight = res[0][0].height;
108 this.windowWinth = res[0][0].width;
109 this.top = res[0][0].bottom - res[0][0].height;
110 this.left = res[0][0].left;
111 });
112 // 矩形骨架元素
113 this.getRectEls();
114 // 圆形骨架元素
115 this.getCircleEls();
116 // 圆角骨架元素
117 this.getFilletEls();
118 },
119 // 矩形元素列表
120 getRectEls() {
121 let query = '';
122 // 在微信小程序中,如果把骨架屏放入组件中使用的话,需要调in(this)上下文为父组件才有效
123 // #ifdef MP-WEIXIN
124 query = uni.createSelectorQuery().in(this.$parent);
125 // #endif
126 // #ifndef MP-WEIXIN
127 query = uni.createSelectorQuery()
128 // #endif
129 query.selectAll('.u-skeleton-rect').boundingClientRect().exec((res) => {
130 this.RectNodes = res[0];
131 });
132 },
133 // 圆角元素列表
134 getFilletEls() {
135 let query = '';
136 // 在微信小程序中,如果把骨架屏放入组件中使用的话,需要调in(this)上下文为父组件才有效
137 // #ifdef MP-WEIXIN
138 query = uni.createSelectorQuery().in(this.$parent);
139 // #endif
140 // #ifndef MP-WEIXIN
141 query = uni.createSelectorQuery()
142 // #endif
143 query.selectAll('.u-skeleton-fillet').boundingClientRect().exec((res) => {
144 this.filletNodes = res[0];
145 });
146 },
147 // 圆形元素列表
148 getCircleEls() {
149 let query = '';
150 // 在微信小程序中,如果把骨架屏放入组件中使用的话,需要调in(this)上下文为父组件才有效
151 // #ifdef MP-WEIXIN
152 query = uni.createSelectorQuery().in(this.$parent);
153 // #endif
154 // #ifndef MP-WEIXIN
155 query = uni.createSelectorQuery()
156 // #endif
157 query.selectAll('.u-skeleton-circle').boundingClientRect().exec((res) => {
158 this.circleNodes = res[0];
159 });
160 }
161 },
162 // 组件被挂载
163 mounted() {
164 // 获取系统信息
165 let systemInfo = uni.getSystemInfoSync();
166 this.windowHeight = systemInfo.windowHeight;
167 this.windowWinth = systemInfo.windowWidth;
168 this.selecterQueryInfo();
169 }
170 }
171</script>
172
173<style lang="scss" scoped>
174 @import "../../libs/css/style.components.scss";
175
176 .skeleton-fade {
177 width: 100%;
178 height: 100%;
179 background: rgb(194, 207, 214);
180 animation-duration: 1.5s;
181 animation-name: blink;
182 animation-timing-function: ease-in-out;
183 animation-iteration-count: infinite;
184 }
185
186 @keyframes blink {
187 0% {
188 opacity: 1;
189 }
190
191 50% {
192 opacity: 0.4;
193 }
194
195 100% {
196 opacity: 1;
197 }
198 }
199</style>