0x00 简介
组件 Spinner
用于页面和区块的加载中状态,页面局部处于等待异步数据或正在渲染过程时,合适的加载动效会有效缓解用户的焦虑。 本文将深入分析组件源码,剖析其实现原理,耐心读完,相信会对您有所帮助。packages/spinner/src/spinner.vue
文件是组件源码实现。 🔗 github 源码 spinner.vue
更多组件剖析详见 👉 📚 Element 2 源码剖析组件总览 。
0x01 Spinner 组件
Spinner.vue
组件是一个隐藏组件,暂未有其他组件使用。
模板创建一个 class 名为el-spinner
的span
元素,包含了一个<circle>
SVG 圆形。
<template>
<span class="el-spinner">
<svg
class="el-spinner-inner"
viewBox="0 0 50 50"
:style="{ width: radius/2 + 'px', height: radius/2 + 'px' }"
>
<circle
class="path"
cx="25"
cy="25"
r="20"
fill="none"
:stroke="strokeColor"
:stroke-width="strokeWidth"
></circle>
</svg>
</span>
</template>
<script>
export default {
name: "ElSpinner",
props: {
type: String,
radius: {
type: Number,
default: 100,
},
strokeWidth: {
type: Number,
default: 5,
},
strokeColor: {
type: String,
default: "#efefef",
},
},
};
</script>
组件提供了以下 prop
属性。
0x02 组件样式
src/spinner.scss
组件样式源码 packages\theme-chalk\src\spinner.scss
使用混合指令 b
嵌套生成组件样式。
// 生成 .el-time-spinner
@include b(time-spinner) {
// ...
}
// 生成 .el-spinner
@include b(spinner) {
// ...
}
// 生成 .el-spinner-inner
@include b(spinner-inner) {
// ...
// 生成 .el-spinner-inner .path
& .path {
// ...
}
}
// 关键帧 CSS动画
@keyframes rotate {
/* ... */
}
@keyframes dash {
/* ... */
}
lib/spinner.css
前文可知使用 gulpfile.js
编译 scss
文件转换为CSS
,经过浏览器兼容、格式压缩,最后生成 packages\theme-chalk\lib\spinner.css
,内容格式如下。
.el-time-spinner {
/* ... */
}
.el-spinner {
/* ... */
}
.el-spinner-inner {
animation: rotate 2s linear infinite;
width: 50px;
height: 50px;
}
.el-spinner-inner .path {
stroke: #ececec;
stroke-linecap: round;
animation: dash 1.5s ease-in-out infinite;
}
@keyframes rotate {
/* ... */
}
@keyframes dash {
/* ... */
}
0x03 CSS 动画
默认的 <circle>
元素展示如下:
使用 @keyframes
at-rule 规则通过在动画序列中定义关键帧(或 waypoints)的样式来控制 CSS 动画序列
定义 <circle>
元素动画关键帧规则 dash
@keyframes dash {
0% {
stroke-dasharray: 1, 150;
stroke-dashoffset: 0;
}
50% {
stroke-dasharray: 90, 150;
stroke-dashoffset: -35;
}
100% {
stroke-dasharray: 90, 150;
stroke-dashoffset: -124;
}
}
.el-spinner-inner .path {
animation: dash 1.5s ease-in-out infinite;
}
添加动画效果后, <circle>
元素展示如下:
定义 <svg>
元素动画关键帧规则 rotate
,用于元素旋转。
@keyframes rotate {
100% {
transform: rotate(360deg);
}
}
.el-spinner-inner {
animation: rotate 2s linear infinite;
}
添加动画效果后, <svg>
元素展示如下:
组件中不同元素的关键帧效果叠加,实现了 loding 动效。
组件提供了 prop 用于自定义效果,代码如下:
<template>
<el-spinner
:radius="300"
:stroke-width="8"
:stroke-color="'#E6A23C'"
></el-spinner>
</template>
组件效果如下:
由于组件样式 .path
定义了 stroke
属性设置了默认值 #ececec;
,导致stroke-color
设置无效。需要移除该属性才能生效。
@include b(spinner-inner) {
// ...
& .path {
// stroke: #ececec;
stroke-linecap: round;
animation: dash 1.5s ease-in-out infinite;
}
}
0x04 📚 参考
"@keyframes",MDN