Element UI 通用图片骨架屏组件

近年来,骨架屏(Skeleton)逐渐成为一种流行的加载动画,其显著增强了用户等待过程中的体验。本文实现了 Vue.js + Element UI 的通用图片骨架屏组件。

感谢 @小灰灰 在研究过程中提供的帮助和创新,编写了组件的部分内容,作了大量重要的工作。

效果预览

源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<template>
<el-skeleton ref="root" :loading="loading" animated>
<template #template>
<el-skeleton-item :class="className" :id="idName" variant="image" :style="{height: skeletonHeight}"/>
</template>
<template>
<img :class="className" :id="idName" :src="src" :alt="alt"/>
</template>
</el-skeleton>
</template>

<script>
export default {
name: "LoadingImage",
props: ["className", "idName", "src", "alt", "height"],
data() {
return {
loading: true,
defaultHeight: "200px",
};
},
mounted() {
this.defaultHeight = (this.$refs.root.$el.clientWidth / 16 * 9) + "px";
let img = new Image();
img.onload = () => {
this.loading = false;
};
img.src = this.src;
},
computed: {
skeletonHeight() {
return this.height !== undefined ? this.height : this.defaultHeight;
},
},
};
</script>

使用

使用时只需传递相应参数即可:

1
<loading-image src="src.webp"></loading-image>

若需要修改图片的样式,只需传递 classid 从外部使用 v-deep 设置 css 即可。

1
<loading-image class-name="class-1" id-name="id-1" src="src.webp"></loading-image>
1
2
3
4
5
6
7
::v-deep .class-1 {
width: 100%;
}

::v-deep #id-1 {
border-radius: 1rem;
}

原理解析

该组件主要由两大功能组成,一是加载图片并切换骨架屏显示,二是智能高度调整。

加载功能

由于默认 loadingtrue,所以 <img> 并不会显示,浏览器也不会请求图片资源。我们在 mounted 时使用 js 请求图片资源。当图片加载完成后,将 loading 设置为 false 且更新 <img>

1
2
3
4
5
let img = new Image();
img.onload = () => {
this.loading = false;
};
img.src = this.src;

智能高度调整

骨架的高度遵循以下规则:

  1. 若传递了高度参数,使用参数设置高度;
  2. mounte 之前使用 200px 作为默认高度;
  3. mounte 之后获取宽度,以 16:9 计算默认高度。

参考文献

  1. Skeleton 骨架屏. Element. [2022-11-16]. (原始内容存档于2022-11-16).

Element UI 通用图片骨架屏组件
https://blog.zhanganzhi.com/zh-CN/2022/11/92e7bb97253e/
作者
Andy Zhang
发布于
2022年11月16日
许可协议