Skip to content

Commit fc628b9

Browse files
cs1707cn3lfs
authored andcommitted
Skeleton: add skeleton component (ElemeFE#21038)
1 parent d8c1091 commit fc628b9

File tree

22 files changed

+1754
-2
lines changed

22 files changed

+1754
-2
lines changed

components.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,5 +80,7 @@
8080
"cascader-panel": "./packages/cascader-panel/index.js",
8181
"avatar": "./packages/avatar/index.js",
8282
"drawer": "./packages/drawer/index.js",
83-
"popconfirm": "./packages/popconfirm/index.js"
83+
"popconfirm": "./packages/popconfirm/index.js",
84+
"skeleton": "./packages/skeleton/index.js",
85+
"skeleton-item": "./packages/skeleton-item/index.js"
8486
}

examples/demo-styles/index.scss

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,4 +44,5 @@
4444
@import "./infinite-scroll.scss";
4545
@import "./avatar.scss";
4646
@import "./drawer.scss";
47+
@import "./skeleton.scss";
4748

examples/demo-styles/skeleton.scss

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
.demo-block.demo-skeleton {
2+
.el-card {
3+
margin-bottom: 16px;
4+
}
5+
6+
.card-header {
7+
display: flex;
8+
justify-content: space-between;
9+
align-items: center;
10+
}
11+
12+
.time {
13+
font-size: 13px;
14+
color: #999;
15+
}
16+
17+
.bottom {
18+
margin-top: 13px;
19+
line-height: 12px;
20+
}
21+
22+
.button {
23+
padding: 0;
24+
min-height: auto;
25+
}
26+
27+
.image {
28+
&.multi-content {
29+
width: 400px;
30+
height: 267px;
31+
}
32+
33+
width: 100%;
34+
display: block;
35+
}
36+
37+
.clearfix:before,
38+
.clearfix:after {
39+
display: table;
40+
content: '';
41+
}
42+
43+
.clearfix:after {
44+
clear: both;
45+
}
46+
}

examples/docs/en-US/skeleton.md

Lines changed: 315 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,315 @@
1+
## Skeleton
2+
3+
When loading data, and you need a rich experience for visual and interactions for your end users, you can choose `skeleton`.
4+
5+
### Basic usage
6+
7+
The basic skeleton.
8+
9+
:::demo
10+
11+
```html
12+
<template>
13+
<el-skeleton />
14+
</template>
15+
```
16+
17+
:::
18+
19+
### Configurable Rows
20+
21+
You can configure the row numbers yourself, we are rendering a title row with 33% width of the others.
22+
23+
:::demo
24+
25+
```html
26+
<el-skeleton :rows="6" />
27+
```
28+
29+
:::
30+
31+
### Animation
32+
We have provided a switch flag indicating whether showing the loading animation, called `animated` when this is true, all children of `el-skeleton` will show animation
33+
34+
:::demo
35+
36+
```html
37+
<el-skeleton :rows="6" animated />
38+
```
39+
40+
:::
41+
42+
### Customized Template
43+
ElementPlus only provides the most common template, sometimes that could be a problem, so you have a slot named `template` to do that work.
44+
45+
Also we have provided different types skeleton unit that you can choose, for more detailed info, please scroll down to the bottom of this page to see the API description. Also, when building your own customized skeleton structure, you should be structuring them as closer to the real DOM as possible, which avoiding the DOM bouncing caused by the height difference.
46+
47+
:::demo
48+
49+
```html
50+
<template>
51+
<el-skeleton style="width: 240px">
52+
<template slot="template">
53+
<el-skeleton-item variant="image" style="width: 240px; height: 240px;" />
54+
<div style="padding: 14px;">
55+
<el-skeleton-item variant="p" style="width: 50%" />
56+
<div
57+
style="display: flex; align-items: center; justify-items: space-between;"
58+
>
59+
<el-skeleton-item variant="text" style="margin-right: 16px;" />
60+
<el-skeleton-item variant="text" style="width: 30%;" />
61+
</div>
62+
</div>
63+
</template>
64+
</el-skeleton>
65+
</template>
66+
```
67+
68+
:::
69+
70+
### Loading state
71+
72+
When `Loading` ends, we always need to show the real UI with data to our end users. with the attribtue `loading` we can control whether showing the DOM. You can also use slot `default` to structure the real DOM element.
73+
74+
:::demo
75+
76+
```html
77+
<template>
78+
<div style="width: 240px">
79+
<p>
80+
<label style="margin-right: 16px;">Switch Loading</label>
81+
<el-switch v-model="loading" />
82+
</p>
83+
<el-skeleton style="width: 240px" :loading="loading" animated>
84+
<template slot="template">
85+
<el-skeleton-item
86+
variant="image"
87+
style="width: 240px; height: 240px;"
88+
/>
89+
<div style="padding: 14px;">
90+
<el-skeleton-item variant="h3" style="width: 50%;" />
91+
<div
92+
style="display: flex; align-items: center; justify-items: space-between; margin-top: 16px; height: 16px;"
93+
>
94+
<el-skeleton-item variant="text" style="margin-right: 16px;" />
95+
<el-skeleton-item variant="text" style="width: 30%;" />
96+
</div>
97+
</div>
98+
</template>
99+
<template>
100+
<el-card :body-style="{ padding: '0px', marginBottom: '1px' }">
101+
<img
102+
src="https://shadow.elemecdn.com/app/element/hamburger.9cf7b091-55e9-11e9-a976-7f4d0b07eef6.png"
103+
class="image"
104+
/>
105+
<div style="padding: 14px;">
106+
<span>Delicious hamberger</span>
107+
<div class="bottom card-header">
108+
<span class="time">{{ currentDate }}</span>
109+
<el-button type="text" class="button">Operation button</el-button>
110+
</div>
111+
</div>
112+
</el-card>
113+
</template>
114+
</el-skeleton>
115+
</div>
116+
</template>
117+
118+
<script>
119+
export default {
120+
data () {
121+
return {
122+
loading: true,
123+
currentDate: '2021-06-01'
124+
}
125+
},
126+
}
127+
</script>
128+
```
129+
130+
:::
131+
132+
133+
### Rendering a list of data
134+
135+
Most of the time, skeleton is used as indicators of rendering a list of data which haven't been fetched from server yet, then we need to create a list of skeleton out of no where to make it look like it is loading, with `count` attribute, you can control how many these templates you need to render to the browser.
136+
137+
138+
:::tip
139+
We do not recommend rendering lots of fake UI to the browser, it will still cause the performance issue, it also costs longer to destroy the skeleton. Keep `count` as small as it can be to make better user experience.
140+
:::
141+
142+
:::demo
143+
144+
```html
145+
<template>
146+
<div style="width: 400px">
147+
<p>
148+
<el-button @click="setLoading">Click me to reload</el-button>
149+
</p>
150+
<el-skeleton style="width:400px" :loading="loading" animated :count="3">
151+
<template slot="template">
152+
<el-skeleton-item
153+
variant="image"
154+
style="width: 400px; height: 267px;"
155+
/>
156+
<div style="padding: 14px;">
157+
<el-skeleton-item variant="h3" style="width: 50%;" />
158+
<div
159+
style="display: flex; align-items: center; justify-items: space-between; margin-top: 16px; height: 16px;"
160+
>
161+
<el-skeleton-item variant="text" style="margin-right: 16px;" />
162+
<el-skeleton-item variant="text" style="width: 30%;" />
163+
</div>
164+
</div>
165+
</template>
166+
<template>
167+
<el-card
168+
:body-style="{ padding: '0px', marginBottom: '1px' }"
169+
v-for="item in lists"
170+
:key="item.name"
171+
>
172+
<img :src="item.imgUrl" class="image multi-content" />
173+
<div style="padding: 14px;">
174+
<span>Delicious hamberger</span>
175+
<div class="bottom card-header">
176+
<span class="time">{{ currentDate }}</span>
177+
<el-button type="text" class="button">Operation button</el-button>
178+
</div>
179+
</div>
180+
</el-card>
181+
</template>
182+
</el-skeleton>
183+
</div>
184+
</template>
185+
186+
<script>
187+
export default {
188+
data() {
189+
return {
190+
loading: true,
191+
currentDate: '2021-06-01',
192+
lists: [],
193+
}
194+
},
195+
mounted() {
196+
this.loading = false
197+
this.lists = [
198+
{
199+
imgUrl:
200+
'https://fuss10.elemecdn.com/a/3f/3302e58f9a181d2509f3dc0fa68b0jpeg.jpeg',
201+
name: 'Deer',
202+
},
203+
{
204+
imgUrl:
205+
'https://fuss10.elemecdn.com/1/34/19aa98b1fcb2781c4fba33d850549jpeg.jpeg',
206+
name: 'Horse',
207+
},
208+
{
209+
imgUrl:
210+
'https://fuss10.elemecdn.com/0/6f/e35ff375812e6b0020b6b4e8f9583jpeg.jpeg',
211+
name: 'Mountain Lion',
212+
},
213+
]
214+
},
215+
methods: {
216+
setLoading() {
217+
this.loading = true
218+
setTimeout(() => (this.loading = false), 2000)
219+
},
220+
},
221+
}
222+
</script>
223+
```
224+
225+
:::
226+
227+
### Avoiding rendering bouncing.
228+
Sometimes API responds very quickly, when that happens, the skeleton just gets rendered to the DOM then it needs to switch back to real DOM, that causes the sudden flashy. To avoid such thing, you can use the `throttle` attribute.
229+
230+
231+
:::demo
232+
233+
```html
234+
<template>
235+
<div style="width: 240px">
236+
<p>
237+
<label style="margin-right: 16px;">Switch Loading</label>
238+
<el-switch v-model="loading" />
239+
</p>
240+
<el-skeleton
241+
style="width: 240px"
242+
:loading="loading"
243+
animated
244+
:throttle="500"
245+
>
246+
<template slot="template">
247+
<el-skeleton-item
248+
variant="image"
249+
style="width: 240px; height: 240px;"
250+
/>
251+
<div style="padding: 14px;">
252+
<el-skeleton-item variant="h3" style="width: 50%;" />
253+
<div
254+
style="display: flex; align-items: center; justify-items: space-between; margin-top: 16px; height: 16px;"
255+
>
256+
<el-skeleton-item variant="text" style="margin-right: 16px;" />
257+
<el-skeleton-item variant="text" style="width: 30%;" />
258+
</div>
259+
</div>
260+
</template>
261+
<template>
262+
<el-card :body-style="{ padding: '0px', marginBottom: '1px'}">
263+
<img
264+
src="https://shadow.elemecdn.com/app/element/hamburger.9cf7b091-55e9-11e9-a976-7f4d0b07eef6.png"
265+
class="image"
266+
/>
267+
<div style="padding: 14px;">
268+
<span>Delicious hamberger</span>
269+
<div class="bottom card-header">
270+
<span class="time">{{ currentDate }}</span>
271+
<el-button type="text" class="button">operation button</el-button>
272+
</div>
273+
</div>
274+
</el-card>
275+
</template>
276+
</el-skeleton>
277+
</div>
278+
</template>
279+
280+
<script>
281+
export default {
282+
data() {
283+
return {
284+
loading: false,
285+
currentDate: '2021-06-01'
286+
}
287+
},
288+
}
289+
</script>
290+
```
291+
:::
292+
293+
### Skeleton Attributes
294+
295+
| Attribute | Description | Type | Acceptable Value | Default |
296+
| ------- | ---------------- | ------- | ------------ | ------ |
297+
| animated | whether showing the animation | boolean | true / false | false |
298+
| count | how many fake items to render to the DOM | number | integer | 1 |
299+
| loading | whether showing the skeleton | boolean | true / false | true |
300+
| rows | numbers of the row, only useful when no template slot were given | number | integer | 4 |
301+
| throttle | Rendering delay in millseconds | number | integer | 0 |
302+
303+
304+
### Skeleton Item Attributes
305+
| Attribute | Description | Type | Acceptable Value | Default |
306+
| ------- | ---------------- | ------- | ------------ | ------ |
307+
| variant | The current rendering skeleton type | Enum(string) | p / text / h1 / h3 / text / caption / button / image / circle / rect | text |
308+
309+
310+
### Skeleton Slots
311+
312+
| Name | Description |
313+
| ---- | ----------- |
314+
| default | Real rendering DOM |
315+
| template | Custom rendering skeleton template |

0 commit comments

Comments
 (0)