首页 > 其他分享 >vue2、vue3 纯SCSS 实现环形进度条

vue2、vue3 纯SCSS 实现环形进度条

时间:2024-07-02 10:34:28浏览次数:1  
标签:SCSS 进度条 default 50% color vue2 innerPercent type props

vue3 纯SCSS 实现环形进度条


<template>
  <view class="flex align-center diygw-col-24 justify-center">
    <view
      class="progress-circle"
      :class="`progress-${innerPercent}`"
    >
      <view class="inner">
        <slot></slot>
      </view>
    </view>
  </view>
</template>
 
<script lang="ts" setup>
const props = defineProps({
  width: {
    type: Number || String,
    default: '56px'
  },
  borderWidth: {
    type: Number || String,
    default: '3px'
  },
  bgColor: {
    type: String,
    default: '#fff'
  },
  notProgressColor: {
    type: String,
    default: '#ddd'
  },
  progressColor: {
    type: String,
    default: '#004898'
  },
  color: {
    type: String,
    default: '#333'
  },
  fontSize: {
    type: String,
    default: '24rpx'
  },
  percent: {
    type: Number,
    default: 0
  },
  animate: {
    type: Boolean,
    default: true
  },
  rate: {
    type: Number,
    default: 5
  }
});

const innerPercent = ref(props.percent);

const complete = computed(() => innerPercent.value == 100);

watch(() => props.percent, (percent) => {
  setPercent();
});

onMounted(() => {
  setPercent();
});

const setPercent = () => {
  if (props.animate) {
    stepTo(true);
  } else {
    innerPercent.value = props.percent;
  }
};
const stateTimer = ref(null)
const clearTimeoutFn = () => {
  if (stateTimer.value) {
    clearTimeout(stateTimer.value);
    stateTimer.value = null;
  }
};

const stepTo = (topFrame = false) => {
  if (topFrame) {
    clearTimeoutFn();
  }
  if (props.percent > innerPercent.value && !complete.value) {
    innerPercent.value = innerPercent.value + 1;
  }
  if (props.percent < innerPercent.value && innerPercent.value > 0) {
    innerPercent.value = innerPercent.value - 1;
  }
  if (innerPercent.value !== props.percent) {
    stateTimer.value = setTimeout(() => {
      stepTo();
    }, props.rate);
  }
};
</script>
 
<style lang="scss" scoped>
.progress-circle {
  $diythemeColor: v-bind('props.progressColor');
  $diybackColor: v-bind('props.notProgressColor');
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  width: v-bind('props.width');
  height: v-bind('props.width');
  border-radius: 50%;
  transition: transform 1s;
  background-color: $diybackColor;
  padding: v-bind('props.borderWidth');
  box-sizing: border-box;

  .inner {
    width: 100%;
    height: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 50%;
    z-index: 1;
    background-color: v-bind('props.bgColor');
  }

  &:before {
    content: '';
    left: 0;
    top: 0;
    position: absolute;
    width: 100%;
    height: 100%;
    border-radius: 50%;
    background-color: $diythemeColor;
  }

  $step: 1;
  $loops: 99;
  $increment: 3.6;
  $half: 50;

  @for $i from 0 through $loops {
    &.progress-#{$i * $step}:before {
      @if $i < $half {
        $nextDeg: 90deg+($increment * $i);
        background-image: linear-gradient(90deg, $diybackColor 50%, transparent 50%, transparent), linear-gradient($nextDeg, $diythemeColor 50%, $diybackColor 50%, $diybackColor);
      }

      @else {
        $nextDeg: -90deg+($increment * ($i - $half));
        background-image: linear-gradient($nextDeg, $diythemeColor 50%, transparent 50%, transparent), linear-gradient(270deg, $diythemeColor 50%, $diybackColor 50%, $diybackColor);
      }
    }
  }

  .progress-number {
    width: 100%;
    line-height: 1;
    text-align: center;
    font-size: v-bind('props.fontSize');
    color: v-bind('props.color');
  }
}
</style>

vue2 纯SCSS 实现环形进度条


<template>
  <view class="flex align-center diygw-col-24 justify-center">
    <view class="progress-circle " :class="'progress-' + innerPercent" :style="{
      '--not-progress-color': notProgressColor,
      '--bg-color': bgColor,
      '--color': color,
      '--progress-color': progressColor,
      '--width': $u.addUnit(width),
      '--font-size': $u.addUnit(fontSize),
      '--border-width': $u.addUnit(borderWidth)
    }">
      <view class="inner">
        <!-- <view class="progress-number">{{ innerPercent }}%</view> -->
        <slot></slot>
      </view>
    </view>
  </view>
</template>
 
<script>
export default {
  props: {
    width: {
      type: Number,
      default: 52
    },
    borderWidth: {
      type: Number,
      default: 3
    },
    bgColor: {
      type: String,
      default: '#fff'
    },
    notProgressColor: {
      type: String,
      default: '#ddd'
    },
    progressColor: {
      type: String,
      default: '#004898'
    },
    color: {
      type: String,
      default: '#333'
    },
    fontSize: {
      type: Number,
      default: 24
    },
    /**
     * 进度(0-100)
     */
    percent: {
      type: Number,
      default: 0
    },
    /**
     * 是否动画
     */
    animate: {
      type: Boolean,
      default: true
    },
    /**
     * 动画速率
     */
    rate: {
      type: Number,
      default: 5
    }
  },
  computed: {
    /**
     * @private
     */
    complete() {
      return this.innerPercent == 100
    }
  },
  watch: {
    percent(percent) {
      this.setPercent()
    }
  },
  data() {
    return {
      innerPercent: 0,
      timeout: null
    }
  },
  mounted() {
    this.setPercent()
  },
  methods: {
    setPercent() {
      if (this.animate) {
        this.stepTo(true)
      } else {
        this.innerPercent = this.percent
      }
    },
    clearTimeout() {
      clearTimeout(this.timeout)
      Object.assign(this, {
        timeout: null
      })
    },
    stepTo(topFrame = false) {
      if (topFrame) {
        this.clearTimeout()
      }
      if (this.percent > this.innerPercent && !this.complete) {
        this.innerPercent = this.innerPercent + 1
      }
      if (this.percent < this.innerPercent && this.innerPercent > 0) {
        this.innerPercent--
      }
      if (this.innerPercent !== this.percent) {
        this.timeout = setTimeout(() => {
          this.stepTo()
        }, this.rate)
      }
    }
  }
}
</script>
 
<style lang="scss" scoped>
.progress-circle {
  --progress-color: #63B8FF;
  --not-progress-color: #ddd;
  --bg-color: #fff;
  --width: 240rpx;
  --border-width: 10rpx;
  --color: #777;
  --font-size: 1.5rem;

  $diythemeColor: var(--progress-color);
  $diybackColor: var(--not-progress-color);
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  width: var(--width);
  height: var(--width);
  border-radius: 50%;
  transition: transform 1s;
  background-color: $diybackColor;
  padding: var(--border-width);

  .inner {
    width: 100%;
    height: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 50%;
    z-index: 1;
    background-color: var(--bg-color);
  }

  &:before {
    content: '';
    left: 0;
    top: 0;
    position: absolute;
    width: 100%;
    height: 100%;
    border-radius: 50%;
    background-color: $diythemeColor;
  }

  $step: 1;
  $loops: 99;
  $increment: 3.6;
  $half: 50;

  @for $i from 0 through $loops {
    &.progress-#{$i * $step}:before {
      @if $i < $half {
        $nextDeg: 90deg+($increment * $i);
        background-image: linear-gradient(90deg, $diybackColor 50%, transparent 50%, transparent), linear-gradient($nextDeg, $diythemeColor 50%, $diybackColor 50%, $diybackColor);
      }

      @else {
        $nextDeg: -90deg+($increment * ($i - $half));
        background-image: linear-gradient($nextDeg, $diythemeColor 50%, transparent 50%, transparent), linear-gradient(270deg, $diythemeColor 50%, $diybackColor 50%, $diybackColor);
      }
    }
  }

  .progress-number {
    width: 100%;
    line-height: 1;
    text-align: center;
    font-size: var(--font-size);
    color: var(--color);
  }
}
</style>

使用

 <CircleProgress
     :percent="item.curSoc"
     style="position: relative;"
     class="full-box">
    <view class="number" style="position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%); width: max-content; white-space: nowrap;">
      <template v-if="item.electricCurrentModel === 1">
        <view style="font-size: 28rpx; font-weight: bold;">{{item.curSoc}}%</view>
        <view style="font-size: 18rpx;">充电中</view>
      </template>
      <view v-else>充电中</view>
    </view>
 </CircleProgress>

标签:SCSS,进度条,default,50%,color,vue2,innerPercent,type,props
From: https://www.cnblogs.com/DL-CODER/p/18279386

相关文章

  • 【鸿蒙学习笔记】基础组件Progress:进度条组件
    官方文档:Progress目录标题作用最全属性迭代进度赋值风格样式作用进度条组件最全属性迭代Progress({value:20,total:100,type:ProgressType.Linear}).color(Color.Green)//颜色.width(200)//大小.height(50)//高度.value(50)//进度可更新,2......
  • 【区分vue2和vue3下的element UI Descriptions 描述列表组件,分别详细介绍属性,事件,方法
    在ElementUI(为Vue2设计)和ElementPlus(为Vue3设计)中,Descriptions(描述列表)组件通常用于展示一系列的结构化信息。然而,需要明确的是,ElementUI官方库中并没有直接名为Descriptions的组件,但在ElementPlus中,该组件是存在的。以下将分别介绍ElementPlus中的De......
  • 【区分vue2和vue3下的element UI Result 结果组件,分别详细介绍属性,事件,方法如何使用,并
    在Vue2中,ElementUI并没有直接提供名为Result的组件。但是,在Vue3的ElementPlus中,Result组件是用来展示操作结果或状态信息的。以下是ElementPlus中Result组件的详细介绍,以及如何在Vue3中使用它。由于Vue2没有该组件,我将只介绍Vue3下的使用。Vu......
  • 对比Vue2/Vue3项目如何自定义插件
    学习目标:对比Vue2/Vue3项目如何自定义插件学习内容:插件(Plugins)是一种能为Vue添加全局功能的工具代码。一个插件可以是一个拥有 install() 方法的对象,也可以直接是一个安装函数本身。安装函数会接收到安装它的应用实例传递给Vue.use()/ app.use() 的额外选项作......
  • 开源项目推荐-vue2+element+axios 个人财务管理系统
    文章目录financialmanagement项目简介项目特色项目预览卫星的实现方式:首次进入卫星效果的实现方式:卫星跟随鼠标滑动的随机效果实现方式:环境准备项目启动项目部署项目地址financialmanagement项目简介vue2+element+axios个人财务管理系统是基于vue2+element+ax......
  • 第二十四节:带你梳理Vue2 : Vue具名插槽/作用域插槽/v-slot指令
    1.具名插槽1.1没有使用具名插槽的问题有的时候我们在使用子组件时,在子组件模板上不同的位置插入不同的内容,只有一个插槽显然没法满足我们的需求,看示例:需求如下:子组件是一篇文章的结构父组件在调用子组件是给文章插入标题,正文,时间信息示例代码如下:<divid=......
  • 实现vue2的响应式原理
    /****基本原理:*1、通过Observer劫持data上的对象并监听data上的所有属性,遍历所有属性,并用Object.defineProperty转化为getter/setter,监听data上属性的的变化*2、将data上的属性挂载到vue的实例上,实例化后可以在vue使用this访问data属性*3、使用Compiler......
  • QianKun vue2 改造主应用 vue3+vite 改造子应用
    一:Vue2改造主应用创建方式:vuecreatevue2-master 1:在vue2项目src下撞见qiankun文件夹用于注册和启动子应用配置创建index.js创建app.js。注册。name要和子应用vite.config.js配置相同。container要和indexView中id相同创建indexView.vue。用于显示微应用......
  • Vue2学习八-Vue核心(生命周期)
    目录17.生命周期17.1什么是生命周期17.2 分析生命周期17.3生命周期总结17.生命周期17.1什么是生命周期<!DOCTYPEhtml><html> <head> <metacharset="UTF-8"/> <title>引出生命周期</title> <!--引入Vue--> <scripttype="text/java......
  • Vue2学习九-Vue组件化编程(非单文件组件、单文件组件)
    18.非单文件组件18.1.基本使用Vue中使用组件的三大步骤: 一、定义组件(创建组件) 二、注册组件 三、使用组件(写组件标签)一、如何定义一个组件? 使用Vue.extend(options)创建,其中options和newVue(options)时传入的那个options几乎一样,但也有点区别; 区别如下: 1.......