写在最前面:
本文是小程序开发中,使用纯css+html实现的进度圆环动画加载效果(换成vue也是一样的)。
如果你的项目可以用echarts,建议还是用插件,手搓不易,这很难评。
实现效果如上图:
HTML部分
<view :class="styles.chargeBox"><view :class="styles.clockFace"><!-- 24 个刻度线 --><viewv-for="i in 24":key="i":class="[styles.tick]":style="{ transform: `rotate(${(i - 1) * 15}deg) translateY(-248rpx)` }"><!-- 特殊刻度数字 --><textv-if="isSpecialTick(i)":class="styles.tickNumber":style="{ transform: `rotate(${-((i - 1) * 15)}deg)` }">{{ getTickNumber(i) }}</text></view><!-- 环形轨道 --><view :class="targetProgress == 100 ? styles.orbitFinsh : styles.orbitTrack" :style="{ '--progress': `${currentProgress}` }"><template v-if="targetProgress > 0 && targetProgress < 100"><!-- 进度条圆角 --><view :class="styles.orbitEnd"></view><!-- 半径上的小圆点 --><view :class="styles.orbitCircle"></view></template><!-- 外层渐变圆环 --><view :class="styles.outerCircle"><view :class="styles.circularTrack"><!-- 最小内层圆环 --><view :class="styles.innerCircle"><view :class="styles.measure"><view :class="styles.num">{{ currentProgress }}<view :class="styles.unit">%</view></view></view></view></view></view></view></view></view>
js部分
const isSpecialTick = (i) => {const angle = (i - 1) * 15;return angle % 90 === 0; // 0°, 90°, 180°, 270°
};const getTickNumber = (i) => {const angle = (i - 1) * 15;switch (angle) {case 0:return '50';case 90:return '75';case 180:return '0';case 270:return '25';default:return '';}
};
const currentProgress = ref(0);
const targetProgress = ref(90);// 挂载后执行动画
onMounted(() => {const interval = setInterval(() => {if (currentProgress.value >= targetProgress.value) {clearInterval(interval);return;}currentProgress.value++;}, 10);
});
css_90">css部分
.chargeBox {display: flex;justify-content: center;align-items: center;position: relative;margin-bottom: 16px;z-index: 9;.clockFace {width: 496px;height: 496px;border-radius: 50%;position: relative;margin: 50px;display: flex;justify-content: center;align-items: center;}.tick {position: absolute;width: 8px; // 刻度线的宽度height: 8px; // 刻度线的高度border-radius: 50%;background-color: var(--color-font-light__3); // 刻度线的颜色top: 50%; // 垂直居中left: 50%; // 水平居中transform-origin: center top; // 设置变换的原点}.specialTick {width: 16px; // 刻度线的宽度height: 16px; // 刻度线的高度border-radius: 50%;background-color: var(--color-font-light__1); // 特殊刻度线的颜色}.tickNumber {position: absolute;top: -35px; // 调整数字的位置left: -5px;transform: translate(-55%, -55%);font-size: 24px;line-height: 1;color: #0000001F;}.orbitFinsh {width: 450px;height: 450px;position: relative;border-radius: 50%;display: flex;justify-content: center;align-items: center;animation: calc(var(--progress) * 1%) 1.5s linear infinite; /* 应用旋转和增长动画 */background: radial-gradient(transparent 0%,#137DF5 calc(var(--progress) * 1%),transparent calc(var(--progress) * 1%),);z-index: 1;}.orbitTrack {width: 450px;height: 450px;position: relative;border-radius: 50%;display: flex;justify-content: center;align-items: center;animation: calc(var(--progress) * 1%) 1.5s linear infinite; /* 应用旋转和增长动画 */background: conic-gradient(from 180deg,#E7EEFE 0%, #137DF5 calc(var(--progress) * 1%),transparent calc(var(--progress) * 1%),);z-index: 1;}.orbitEnd {position: absolute;top: 0;left: 0;width: 100%;height: 100%;border-radius: 50%;transform: rotate(calc(180deg + (var(--progress) * 3.6deg))); transform-origin: center center;animation: transform 1.5s linear infinite; }.orbitEnd::before {position: absolute;display: inline-block;content: "";width: 15px;height: 16px;border-radius: 50%;background-color: #137DF5;top: 0%;left: 47.9%;}.orbitCircle {position: absolute;top: 0;left: 0;width: 100%;height: 100%;border-radius: 50%;transform: rotate(calc(180deg + var(--progress) * 3.6deg));animation: transform 1.5s linear infinite; transform-origin: center center;z-index: 2;}.orbitCircle::after {position: absolute;display: inline-block;content: "";width: 22px;height: 22px;border-radius: 50%;border: 5.41px solid #fff;background-color: #137DF5;top: 8%;left: 46.5%;}.outerCircle {width: 420px;height: 420px;background: rgba(227,255,241,0.41);box-shadow: inset 0px 0px 54px 0px rgba(99,191,255,0.48);border-radius: 50%;display: flex;justify-content: center;align-items: center;position: relative;overflow: visible;.innerCircle {width: 272px;height: 272px;background: radial-gradient(42% at 73% 53%, #FFFFFD 100%, #D2E2FF 100%);box-shadow: 0px 22px 27px -14px rgba(54,110,244,0.08), 0px 43px 65px 5px rgba(54,110,244,0.04), 0px 16px 81px 14px rgba(54,110,244,0.23), inset 0px 0px 32px 0px #FFFFFF;border-radius: 50%;z-index: 10; display: flex;justify-content: center;align-items: center;}.circularTrack {width: 272px;height: 272px;border-radius: 50%;display: flex;justify-content: center;align-items: center;background: radial-gradient(#FFFFFD 0%, #D2E2FF 100%,);}}.measure {font-family: Bebas, Bebas;font-weight: 500;color: #137DF5;display: flex;justify-content: flex-end;align-items: flex-end;.num {font-size: 96px;line-height: 96px;position: relative;}.unit {position: absolute;bottom: 0;right: -30px;font-size: 36px;line-height: 46px;text-align: left;display: inline-block;}}}
end!
希望记录的问题能帮助到你~