[Uni-app] 微信小程序的圆环进度条

效果图:

组件完整代码如下:

<template>
  <view class="base-style"
    :style="'position: relative;width: ' + diameter + 'px;height: ' + diameter + 'px;display: flex;flex-direction: row;background-color: ' + bgColor + ';'">
    <!-- 左半圆和右半圆都要经历下面的5步:
    [第1步]第1层限定区域; 
    [第2步]第2层决定显示一个整圆的左半边还是右半边; 
    [第3步]第3层先使用激活颜色绘制一个圆环, 再添加一个同级且宽度为区域一半的盒子A;
    [第4步]在盒子A中再使用圆环底色绘制一个圆环, 此时整个圆环是 '左一半是激活颜色、右一半是圆环底色', 但这个圆环同时只能被看到一半;
    [第5步]旋转第2层。 -->

    <!-- 左半圆 -->
    <view class="base-style" :style="firstLayerViewStyle">
      <view :style="secondLayerViewStyle + secondLayerForLeft">
        <!-- 使用激活颜色绘制一个圆环。 -->
        <view :style="thirdLayerStyle">
        </view>
        <!-- 再使用背景色遮盖同级圆环的一半。 -->
        <view class="base-style" :style="thirdLayerStyleForBg">
          <view :style="fourthLayerStyleForBg" />
        </view>
        <view v-if="0 < ePercent && ePercent < 0.5" :style="endPointStyle + endPointStyleForLeft" />
      </view>
    </view>

    <!-- 右半圆 -->
    <view class="base-style" :style="firstLayerViewStyle">
      <!-- 适配:为了避免右侧遮盖显示不全 此处向左多移动了1px -->
      <view :style="secondLayerViewStyle + 'left: ' + (- diameter / 2 - 1) + 'px;' + secondLayerForRight">
        <!-- 使用激活颜色绘制一个圆环。 -->
        <view :style="thirdLayerStyle">
        </view>
        <!-- 再使用背景色遮盖同级圆环的一半。 -->
        <view class="base-style" :style="thirdLayerStyleForBg">
          <view :style="fourthLayerStyleForBg" />
        </view>
        <view v-if="ePercent > 0.5" :style="endPointStyle + endPointStyleForRight" />
      </view>
    </view>

    <view v-if="0.5 == ePercent" :style="endPointStyle + 'background-color: ' + this.hoopBgColor + ';'" />
    <!-- #ifdef APP-PLUS -->
    <!-- 处理现象: 安卓App的顶部和底部会有一个小白点。 -->
    <!-- <view v-if="ePercent > 0.5" :style="'position: absolute;top: 0;' + repairPointStyle" /> -->
    <!-- <view v-if="1.0 == ePercent" :style="'position: absolute;bottom: 0;' + repairPointStyle" /> -->
    <!-- #endif -->
  </view>
</template>

<!-- 组件名称: 圆环进度条。
     启发地址: https://www.cnblogs.com/jr1993/p/4677921.html 。
     编者信息: 867003077@qq.com 。 -->
<script>
  export default {
    name: 'progressCircle',
    props: {
      // 背景色(不宜设置为透明 否则 需要 在 左thirdLayer 的外面 再嵌套一个盒子)。
      bgColor: {
        type: String,
        default: '#FFFFFF'
      },
      // 圆环的外直径(单位px)。
      diameter: {
        type: Number,
        default: 250
      },
      // 圆环线条的厚度(单位px)。
      hoopThickness: {
        type: Number,
        default: 8
      },
      // 圆环底色(灰色的圆环)。
      hoopBgColor: {
        type: String,
        // default: 'transparent'
        default: '#F3F3F3'
      },
      // 圆环激活部分的颜色。
      hoopColor: {
        type: String,
        default: '#FF4C20'
      },
      // 圆环进度百分比值(其值范围在0到1之间)。
      percent: {
        type: [Number, String],
        default: 0,
        validator: val => {
          return val >= 0 && val <= 1;
        },
      },
      animate: {
        type: Boolean,
        default: false,
      },
    },
    data() {
      return {
        targetPercent: 0,
        ePercent: 0,
        showTimer: undefined,
      };
    },
    watch: {
      percent: {
        handler: function() {
          console.log('progressCircle_watch_percent', this.percent);
          this.loadData();
        },
      },
    },
    computed: {
      firstLayerViewStyle() {
        return 'position: relative;width: ' + (this.diameter / 2) +
          'px;height: ' + this.diameter + 'px;';
      },
      secondLayerViewStyle() {
        return 'box-sizing: border-box;position: absolute;top: 0;width: ' + this.diameter +
          'px;height: ' + this.diameter + 'px;';
      },
      thirdLayerStyle() {
        return 'box-sizing: border-box;width: ' + this.diameter + 'px;height: ' + this.diameter +
          'px;border-radius: ' + (this.diameter / 2) +
          'px;border-width: ' + this.hoopThickness +
          'px;border-style: solid;border-color: ' + this.hoopColor + ';';
      },
      thirdLayerStyleForBg() {
        return 'box-sizing: border-box;position: absolute;top: 0;left: ' + (this.diameter / 2) + 'px;width: ' +
          this.diameter + 'px;height: ' + this.diameter + 'px;background-color: ' + this.bgColor + ';';
      },
      fourthLayerStyleForBg() {
        return 'box-sizing: border-box;margin-left: ' + (-this.diameter / 2) + 'px;width: ' + this.diameter +
          'px;height: ' +
          this.diameter + 'px;border-radius: ' + (this.diameter / 2) + 'px;border-width: ' +
          this.hoopThickness + 'px;border-style: solid;border-color: ' + this.hoopBgColor + ';';
      },
      secondLayerForLeft() {
        let angle = 0;
        if (this.ePercent < 0.5) {
          angle += (180 * (this.ePercent - 0.5) / 0.5);
        }
        // #ifdef APP-PLUS
        return 'left: 0;transform: rotate(' + angle + 'deg);';
        // #endif
        // #ifdef MP-WEIXIN
        return 'left: 0;transform: rotate(' + angle + 'deg);-webkit-transform: rotate(' + angle + 'deg);';
        // #endif
      },
      secondLayerForRight() {
        let angle = 0;
        if (this.ePercent > 0.5) {
          angle += (180 * (this.ePercent - 0.5) / 0.5);
        }
        // #ifdef APP-PLUS
        return 'right: 0;transform: rotate(' + angle + 'deg);';
        // #endif
        // #ifdef MP-WEIXIN
        return 'right: 0;transform: rotate(' + angle + 'deg);-webkit-transform: rotate(' + angle + 'deg);';
        // #endif
      },
      // repairPointStyle() {
      // 	return 'left: ' + (this.diameter - this.hoopThickness) / 2 + 'px;width: ' +
      // 		this.hoopThickness + 'px;height: ' + this.hoopThickness + 'px;border-radius: ' +
      // 		this.hoopThickness / 2 + 'px;background-color: ' + this.hoopColor + ';';
      // },
      endPointStyle() {
        // 结束点圆心圈直径。
        const _circleCenterRadius = 2;
        return 'box-sizing: border-box;position: absolute;top: 0;left: ' + (this.diameter - this.hoopThickness) / 2 +
          'px;width: ' +
          this.hoopThickness + 'px;height: ' + this.hoopThickness + 'px;border-radius: ' + (this.hoopThickness / 2) +
          'px;border-width: ' + (this.hoopThickness / 2 - _circleCenterRadius) +
          'px;border-style: solid;border-color: ' +
          this.hoopColor + ';';
      },
      endPointStyleForLeft() {
        return 'background-color: ' + ((this.ePercent > 0.5) ? this.hoopColor : this.hoopBgColor) + ';';
      },
      endPointStyleForRight() {
        return 'background-color: ' + ((1 == this.ePercent) ? this.hoopColor : this.hoopBgColor) + ';';
      },
    },
    mounted() {
      console.log('progressCircle_mounted');
      this.loadData();
    },
    methods: {
      loadData() {
        this.targetPercent = parseFloat(this.percent);
        console.log('progressCircle_loadData');
        if (!this.animate) {
          this.ePercent = this.targetPercent;
        } else {
          let _this = this;
          this.ePercent = 0;
          this.showTimer && clearInterval(this.showTimer);
          this.showTimer = setInterval(() => {
            let tempPercent = _this.ePercent + 0.1;
            if (tempPercent < _this.targetPercent) {
              _this.ePercent = tempPercent;
              return;
            };
            _this.ePercent = _this.targetPercent;
            clearInterval(_this.showTimer);
          }, 200);
        }
      }
    }
  }
</script>

<style scoped>
  .base-style {
    box-sizing: border-box;
    /* 溢出隐藏 */
    overflow: hidden;
  }
</style>

调用页面:

<template>
  <view class="my-page-container" :style="{ 'height': pageBoxH + 'px' }" @click="currentPercent=0.8">
    <progress-circle class="mine-member-level-progress" :diameter="180" :hoopThickness="10" :hoopColor="'orange'"
      :percent="currentPercent" :animate="true" />
  </view>
</template>

<script>
  /** 演示页面 */
  import progressCircle from "@/components/progress-circle/index.vue";
  // import {
  //   queryDetail,
  // } from '@/api/mine.js';
  export default {
    name: 'myDemo',
    components: {
      progressCircle,
    },
    data() {
      return {
        pageBoxH: 1000,
        currentPercent: 0.25,
      };
    },
    beforeCreate() {
      console.log('beforeCreate enter');
    },
    created() {
      console.log('created enter');
    },
    mounted() {
      console.log('mounted enter');
    },
    onLoad(option) {
      console.log('onLoad enter');
    },
    onReady() {},
    methods: {},
  }
</script>

<style scoped>
  .my-page-container {
    background-color: white;
    box-sizing: border-box;
    padding: 10px 10px 50px 10px;
    display: flex;
    flex-direction: column;
  }
</style>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/470637.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

RK3588+FPGA+AD+AI的智能数据采集与分析解决方案

RK3588是瑞芯微新一代旗舰级高端处理器&#xff0c;具有高算力、低功耗、超强多媒体、丰富数据接口等特点。搭载四核A76四核A55的八核CPU和ARM G610MP4 GPU&#xff0c;内置6.0TOPs算力的NPU。 RK3588复旦微FPGA方案 有五大技术优势 1. 内置多种功能强大的嵌入式硬件引擎&…

【Linux(1)】Linux的一些基本指令(补充上一篇)

思维导图 学习内容 通过上面的学习目标&#xff0c;我们可以列出要学习的内容&#xff1a; linux的一些指令&#xff1a;cd mkdir cp touch which rm cat alias 一些基本的概念&#xff1a;指令的概念&#xff0c;用户家目录是什么...... 一、Linux的一些指令 1.1 重新认识…

基于Spring Boot共享单车信息系统的设计与实现

摘 要 快速发展的社会中&#xff0c;人们的生活水平都在提高&#xff0c;生活节奏也在逐渐加快。为了节省时间和提高工作效率&#xff0c;越来越多的人选择利用互联网进行线上打理各种事务&#xff0c;然后线上管理系统也就相继涌现。与此同时&#xff0c;人们开始接受方便的生…

Opencv入门---绘图篇

目录 一、cv.line() 二,cv.cricle() 三&#xff0c;cv2.rectangle() 一、cv.line() cv.line()是 OpenCV 库中用于在图像上绘制直线的函数。它可以在图像上绘制一条直线&#xff0c;指定直线的起始点和结束点。 函数的语法如下&#xff1a; cv.line(img, pt1, pt2, color, th…

[LLM] 大模型基础|预训练|有监督微调SFT | 推理

现在的大模型在进行预训练时大部分都采用了GPT的预训练任务&#xff0c;即 Next token prediction。 要理解大语言模型&#xff08;LLM&#xff09;&#xff0c;首先要理解它的本质&#xff0c;无论预训练、微调还是在推理阶段&#xff0c;核心都是next token prediction&#…

dockerfile文件编写

文章目录 dockerfile是什么Dockerfile常用指令1. FROM2. MAINTAINER3. WORKDIR4.COPY5.ADD6.ENV7.RUN8.CMD9.ENTRYPOINT dockerfile是什么 Dockerfile是一个文本配置文件&#xff0c;用于自动化构建Docker镜像。 Dockerfile是由一系列命令和参数构成的脚本&#xff0c;它指导D…

zookeeper快速入门(合集)

zookeeper作为一个分布式协调框架&#xff0c;它的创建就是为了方便或者简化分布式应用的开发。除了服务注册与发现之外&#xff0c;它还能够提供更多的功能&#xff0c;但是对于入门来说&#xff0c;看这一篇就够了。后续会讲zookeeper的架构设计与原理&#xff0c;比如zookee…

resize-observer源码解读

resize-observer github 地址&#xff1a;https://github.com/devrelm/resize-observer 本地启动 npm installnpm startnode 18.16.0 (npm 9.5.1) 启动失败报错 node:internal/crypto/hash:71this[kHandle] new _Hash(algorithm, xofLen);^Error: error:0308010C:digital …

1、初识JVM

一、JVM是什么&#xff1f; JVM的英文全称是 Java Virtual Machine&#xff0c;其中文译名为Java虚拟机。它在本质上就是是一个运行在计算机上的程序&#xff0c;他的职责是运行Java字节码文件。 JVM执行流程如下 二、JVM有哪些功能&#xff1f; 2.1 解释和运行 对字节码文…

【Web技术应用基础】HTML(1)——简单界面

题目1&#xff1a; <!DOCTYPE html> <html><head><meta charset"utf-8"><title>Hello world</title></head> <body bgcolor"F6F3D6"><!--用HTML语言向世界打声招呼吧&#xff01;--><h1 align&…

电脑怎么快速重装系统win7

电脑重装系统是解决软件问题、提升系统性能的常用手段。随着技术发展,一键重装系统成为了许多用户的首选方法,因为它简化了繁琐的操作步骤,节省了大量时间。尤其是对于非技术人员来说,一键重装提供了一种快速高效且不易出错的系统安装方式。如果你需要快速重装win7,那么可…

Spring Boot 自动化单元测试类的编写过程

前言 Web环境模拟测试 企业开发不仅要保障业务层与数据层的功能安全有效&#xff0c;也要保障表现层的功能正常。但是我们一般对表现层的测试都是通过postman手工测试的&#xff0c;并没有在打包过程中代码体现表现层功能被测试通过。那么能否在测试用例中对表现层进行功能测…

Android 项目实战,APP开发,含源码

Android 项目实战&#xff0c;APP开发&#xff0c;含源码 源码项目详情 源码项目详情 切鱼达人&#xff0c;Android休闲游戏开发 打砖块&#xff0c;Android休闲小游戏开发 “牛弹琴”&#xff0c;Android 弹钢琴 app 开发 2048 数字合成大作战&#xff0c;Android小游戏开…

NCV4276BDT50RKG低压差稳压器芯片中文资料PDF数据手册规格书引脚图参数价格

产品概述&#xff1a; NCV4276B是一款输出电流400 mA集成式低压差稳压器系列&#xff0c;设计用于恶劣的汽车环境。它包括宽工作温度和输入电压范围。该器件提供固定和可调电压版本&#xff0c;输出电压精度为 2%。它具有高峰值输入电压容差和反向输入电压保护。它还提供过流保…

【研发管理】产品经理-基础认知

导读&#xff1a;产品经理&#xff08;Product Manager&#xff09;是一个负责产品的全周期管理的职位&#xff0c;他们不仅参与产品的设计、开发、推广和销售&#xff0c;还涉及到产品的市场调研、用户需求分析、竞争分析、产品规划、产品测试以及后续的产品迭代等多个环节。产…

使用Redis做缓存的小案例

如果不了解Redis&#xff0c;可以查看本人博客&#xff1a;Redis入门 Redis基于内存&#xff0c;因此查询速度快&#xff0c;常常可以用来作为缓存使用&#xff0c;缓存就是我们在内存中开辟一段区域来存储我们查询比较频繁的数据&#xff0c;这样&#xff0c;我们在下一次查询…

Hive 数据迁移与备份

迁移类型 同时迁移表及其数据&#xff08;使用import和export&#xff09; 迁移步骤 将表和数据从 Hive 导出到 HDFS将表和数据从 HDFS 导出到本地服务器将表和数据从本地服务器复制到目标服务器将表和数据从目标服务器上传到目标 HDFS将表和数据从目标 HDFS 上传到目标 Hiv…

设计模式学习笔记 - 设计模式与范式 - 创建型:1.单例模式(上):为什么说支持懒加载的双重校验不必饿汉式更优?

今天开始正式学习设计模式。经典的设计模式有 23 种。其中&#xff0c;常用的并不是很多&#xff0c;可能一半都不到。作为程序员&#xff0c;最熟悉的设计模式&#xff0c;肯定包含单例模式。 本次单例模式的讲解&#xff0c;希望你搞清楚下面这样几个问题。&#xff08;第一…

Redis一些命令(2)

启动命令&#xff1a; redis-server /myredis/redis.conf&#xff08;指定配置文件&#xff09; redis-cli -a 123456 -p 6379&#xff08;-a 密码 -p 端口号&#xff09; redis-cli -a 123456 --raw&#xff08;解决中文乱码&#xff09; 关闭命令&#xff1a; redis-cli…

万用表革新升级,WT588F02BP-14S语音芯片助力智能测量新体验v

万能表功能&#xff1a; 万能表是一款集多功能于一体的电子测量工具&#xff0c;能够精准测量电压、电流、电阻等参数&#xff0c;广泛应用于电气、电子、通信等领域。其操作简便、测量准确&#xff0c;是工程师们进行电路调试、故障排查的得力助手&#xff0c;为提升工作效率…