svg或css,写loading圆环和百分比

5,551 阅读8分钟

TL;DR

  • svg写圆环就是利用stroke-dasharray
  • 纯css写圆环是利用border-radius rect rotate
  • 大约就是这种效果
    圆环
    圆环

svg写圆环

css的步骤很多,可以的话优先svg写圆环。

<!-- 本地或者线上跑个demo 修改 stroke-dasharray="0 1069"的第一个值就能看到圆环-->
<svg width="440" height="440">
    <!-- 底部的灰色背景圆环 -->
    <circle cx="220" cy="220" r="170" stroke-width="50" stroke="#D1D3D7" fill="none"></circle>
    <!-- 需要显示的圆环  通过修改 stroke-dasharray="0 1069"的0值那块,(角度/360) = 圆弧长度/周长  这里的圆弧长度就是第一个值-->
    <circle cx="220" cy="220" r="170" stroke-width="50" stroke="#00A5E0" fill="none" transform="matrix(0,-1,1,0,0,440)" stroke-dasharray="0 1069"></circle>
    <!-- transform="matrix(0,-1,1,0,0,440)"这个是让实线从12点开始 需要研究的话 文章末尾有相关链接 -->
</svg>

vue写个动态圆环组件

  • 自定义:圆环显示的百分比、外圆环的直径、圆环宽度、颜色、圆环内文字以及文字大小
  • 使用方式 <ring rate="0.6" size="60" stroke-width="10" stroke-color="#8C95FF" text="及格" text-size="30"/>
  • 组件的具体代码如下
<template>
<div class="parent-element-center">
  <svg :width="diameterShow" :height="diameterShow" :viewbox="viewbox">
    <circle :cx="size" :cy="size" :r="raduisActual" :stroke-width="strokeWidth" stroke="#eee" fill="none"></circle>
    <circle v-if="rate" :text="text" :cx="size" :cy="size" :r="raduisActual" :stroke-width="strokeWidth" :stroke="strokeColor" fill="none" :transform="transform" :stroke-dasharray="strokeDasharray" stroke-linecap="round"></circle>
  </svg>
  <div class="element-center" :style="textStyle">{{ text }}</div>
</div>
</template>
<script>
export default {
  props: {
    // 圆环外圈的直径
    size: {
      default: 175
    },
    // 圆环的小宽度
    strokeWidth: {
      default: 5
    },
    // 圆环的颜色
    strokeColor: {
      default: '#00D476'
    },
    // 圆环显示的百分比 这边是小数
    rate: {
      default: 0.5
    },
    // 圆环里面的文字 这里的文字如果跟rate息息相关 可以放到computed计算
    text: {
      default: 50
    },
    // 圆环里面的文字的fontSize大小
    textSize: {
      default: 20
    }

  },
  computed: {
    raduisActual () {
      return this.size - this.strokeWidth
    },
    diameterShow () {
      return 2 * this.size
    },
    viewbox () {
      return `0 0 ${this.diameterShow} ${this.diameterShow}`
    },
    strokeDasharray () {
      const perimeter = Math.PI * 2 * this.raduisActual
      const showLength = this.rate * perimeter - 3
      return `${showLength} 1000`
    },
    transform () {
      return `matrix(0,-1,1,0,0,${this.diameterShow})`
    },
    textStyle () {
      let res = {}
      res.fontSize = `${this.textSize}px`
      return res
    }
  }
}
</script>
<style scoped>
      .parent-element-center{
        position: relative;display: inline-block;
      }
      .element-center {
        position: absolute;
        left: 50%;
        top: 50%;
        transform: translate(-50%, -50%);
        font-size:40px;
        font-weight: bold;
      }
</style>

纯css 写圆环

逻辑有点复杂,所以按步骤拆分了

1. 写个圆。

so easy。设个宽高,设置radius,搞定。

<div class="circle" style="width: 100px;height:100px;border-radius:100px;background-color: skyblue;">

2. 写个圆环。

有点难度。细细一想,加个border, 背景色干掉,yeah~。 这个逻辑得记住,也就是圆变成圆环两步:

  • 背景色处理(背景色不设置,或者背景色是白色之类的hack)
  • 加个border
<div class="ring" style="width: 100px;height:100px;border-radius:100px;border:4px solid skyblue;">

3.显示半个圆环。

哟,嗯,拿个方块,盖住右边不就行了。这边想再升级下,试试用clip属性。

<!-- 圆环用到了border,计算一半的时候总是计算border很是憋手,索性加个 box-sizing: border-box; -->
<div class="left-half-ring"  style="width: 100px;height:100px;border-radius:100px;border:4px solid skyblue;position:absolute;clip:rect(0 50px 100px 0);box-sizing: border-box;"></div>
<div class="right-half-ring"  style="width: 100px;height:100px;border-radius:100px;border:4px solid skyblue;position:absolute;clip:rect(0 100px 100px 50px);box-sizing: border-box;"></div>


<!-- 当然 如果不想用 box-sizing: border-box; 也可以 代码如下 注意计算的clip-->
<div class="left-half-ring"  style="width: 100px;height:100px;border-radius:100px;border:4px solid skyblue;position:absolute;clip:rect(0 54px 108px 0);"></div>

4.一个圆环,左边和右边不同色

想想就是上面的拼一波呗~

<div style="width: 100px;height:100px;position: relative;">
    <div class="left-half-ring"  style="width: 100px;height:100px;border-radius:100px;border:4px solid blueviolet;position:absolute;clip:rect(0 50px 100px 0);box-sizing: border-box;"></div>
    <div class="right-half-ring"  style="width: 100px;height:100px;border-radius:100px;border:4px solid skyblue;position:absolute;clip:rect(0 100px 100px 50px);box-sizing: border-box;"></div>
</div>

5.两个圆环交叉

就是两个圆环有重叠的部分,其实就是将圆环旋转下,这里为了后期的铺垫,将左边的旋转,右边的作为底色。为了突出层级关系,用到z-index

<div style="width: 100px;height:100px;position: relative;">
    <div class="bg-right-half-ring"  style="width: 100px;height:100px;border-radius:100px;border:4px solid #000;position:absolute;clip:rect(0 100px 100px 50px);box-sizing: border-box;z-index: 1;"></div>
    <div class="front-left-half-ring"  style="width: 100px;height:100px;border-radius:100px;border:4px solid rgba(0,200,0,0.7);position:absolute;clip:rect(0 50px 100px 0);box-sizing: border-box;z-index: 2;transform: rotate(60deg);"></div>
</div>

6.怎么将左边非重叠的部分隐藏掉,只显示重叠部分

其实就是再拿个半圆放在左边部分,这个半圆的颜色和底色一致,造成假象。 这时候,其实通过控制front-left-half-ring的rotate能得到小于180度以内的圆弧

<div style="width: 100px;height:100px;position: relative;">
    <div class="bg-right-half-ring"  style="width: 100px;height:100px;border-radius:100px;border:4px solid #000;position:absolute;clip:rect(0 100px 100px 50px);box-sizing: border-box;z-index: 1;"></div>
    <div class="front-left-half-ring"  style="width: 100px;height:100px;border-radius:100px;border:4px solid rgba(0,200,0,0.7);position:absolute;clip:rect(0 50px 100px 0);box-sizing: border-box;z-index: 2;transform: rotate(60deg);"></div>
    <!-- 遮掉左边的非重叠部分 -->
    <div class="bg-left-half-ring"  style="width: 100px;height:100px;border-radius:100px;border:4px solid #000;position:absolute;clip:rect(0 50px 100px 0);box-sizing: border-box;z-index: 3;"></div>
</div>

7.显示超过180度的圆环

上面的超过180度就有毛病了,毕竟我们只有半个圆弧。那怎么办呢。继续制造假象! 说起来你可能不想相信,就是再写个右半圆,旋转,原来的保持不动。

<div style="width: 100px;height:100px;position: relative;">
    <div class="bg-right-half-ring"  style="width: 100px;height:100px;border-radius:100px;border:4px solid #000;position:absolute;clip:rect(0 100px 100px 50px);box-sizing: border-box;z-index: 1;"></div>
    <div class="front-left-half-ring"  style="width: 100px;height:100px;border-radius:100px;border:4px solid rgba(0,200,0,0.7);position:absolute;clip:rect(0 50px 100px 0);box-sizing: border-box;z-index: 2;transform: rotate(180deg);"></div>
    <div class="bg-left-half-ring"  style="width: 100px;height:100px;border-radius:100px;border:4px solid #000;position:absolute;clip:rect(0 50px 100px 0);box-sizing: border-box;z-index: 3;"></div>
    <!-- 想要240度圆环的话  这边旋转 240-180=60 -->
    <div class="right-half-ring"  style="width: 100px;height:100px;border-radius:100px;border:4px solid rgba(0,200,0,0.7);position:absolute;clip:rect(0 100px 100px 50px);box-sizing: border-box;z-index: 4;transform: rotate(60deg);"></div>
</div>

上面的颜色仅仅为了理解,为了显示完美,请将rgba(0,200,0,0.7)的透明度去掉,效果就很完美了。

8.能显示百分比的圆环

其实直接写个标签在里面,然后(旋转的度数/360 = 百分比),以此求出旋转的度数。

<div style="width: 100px;height:100px;position: relative;display: flex;justify-content: center;align-items: center;">
    <div class="bg-right-half-ring"  style="width: 100px;height:100px;border-radius:100px;border:4px solid #000;position:absolute;clip:rect(0 100px 100px 50px);box-sizing: border-box;z-index: 1;"></div>
    <!-- 72/360=20% -->
    <div class="front-left-half-ring"  style="width: 100px;height:100px;border-radius:100px;border:4px solid rgba(0,200,0,0.7);position:absolute;clip:rect(0 50px 100px 0);box-sizing: border-box;z-index: 2;transform: rotate(72deg);"></div>
    <div class="bg-left-half-ring"  style="width: 100px;height:100px;border-radius:100px;border:4px solid #000;position:absolute;clip:rect(0 50px 100px 0);box-sizing: border-box;z-index: 3;"></div>
    <!-- 想要240度圆环的话  这边旋转 240-180=60 -->
    <div class="right-half-ring"  style="width: 100px;height:100px;border-radius:100px;border:4px solid rgba(0,200,0,0.7);position:absolute;clip:rect(0 100px 100px 50px);box-sizing: border-box;z-index: 4;transform: rotate(60deg);"></div>
    <span id="progress">20%</span>
</div>

无意中发现又是这个大神写的,大神就是大神
张鑫旭大神的rect解释
张鑫旭大神svg画loading
张鑫旭大神多彩圆环的实现
张鑫旭大神矩阵的理解