当前位置: 首页 > news >正文

纯css实现环形进度条+动画加载效果

写在最前面:

本文是小程序开发中,使用纯css+html实现的进度圆环动画加载效果(换成vue也是一样的)。
如果你的项目可以用echarts,建议还是用插件,手搓不易,这很难评。

在这里插入图片描述
实现效果如上图:

HTML部分

<view :class="styles.chargeBox">
                <view :class="styles.clockFace">
                    <!-- 24 个刻度线 -->
                    <view
                        v-for="i in 24"
                        :key="i"
                        :class="[styles.tick]"
                        :style="{ transform: `rotate(${(i - 1) * 15}deg) translateY(-248rpx)` }">
                        <!-- 特殊刻度数字 -->
                        <text
                            v-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部分

.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!
希望记录的问题能帮助到你~

相关文章:

  • QScreen 捕获屏幕(截图)
  • 智能舵机:AI融合下的自动化新纪元
  • Postman 如何模拟 Request Payload 发送请求?
  • MySQL 性能优化:索引优化与查询优化
  • Scikit-learn全攻略:从入门到工业级应用
  • MQ的数据一致性,如何保证?
  • 网络基础:五层模型
  • 深入理解Spring Data JPA:简化Java持久层开发
  • 探索 curl ipinfo.io:从命令行获取你的网络身份卡!!!
  • 在Git仓库的Readme上增加目录页
  • 【LLM】Llama Factory:Windows部署全流程
  • linux如何查看系统版本
  • WinDbg. From A to Z! 笔记(一)
  • 项目代码第8讲【数据库基础知识】:SQL(DDL、DML、DQL、DCL);函数(聚合、字符串、数值、日期、流程);约束;多表查询;事务
  • 西域平台商品详情接口设计与实现‌
  • 电容式电压互感器在线监测系统
  • Uni-app入门到精通:tabBar节点实现多页面的切换
  • Open GL ES ->模型矩阵、视图矩阵、投影矩阵等变换矩阵数学推导以及方法接口说明
  • 深入解析 JSON-RPC:从基础到高级应用
  • VUE3+VITE 爬坑笔记
  • 当农民跨进流动的世界|劳动者的书信①
  • 金融监管总局修订发布《行政处罚办法》,7月1日起施行
  • 司法服务保障西部陆海新通道建设,最高法专门发文
  • 看展览|建造上海:1949年以来的建筑、城市与文化
  • 连演三场,歌剧《义勇军进行曲》在上海西岸大剧院上演
  • 中方会否公布铁线礁的领海基线?外交部:中方执法活动旨在反制菲方侵权挑衅