vue+css 利用transform属性实现圆环效果(一)

1,993 阅读4分钟

项目中的需求,本来可以使用插件实现的,也有现成可用的,但是...我偏偏想要用css来实现一个,所以,查了一些相关资料、文章,然后......就掉进了一个大坑

效果如下

搞着搞着,遇到的问题越来越多,这可是超出预期了呀!但是,都已经这样了,更不能半途而废,于是,就有了这篇文章,记录一下。

预计的浏览器兼容情况:Chrome、FF不用说了,IE就是只兼容9以上的。

技术: vue + css

思路挺简单的,就是利用csstransform: rotate()属性来完成,当然了分数是变化的,为了在圆环中动态展示不同的分数,具体的变化还是用js来控制。

先定义一个外部容器,宽高相同的正方形,然后添加左右两个子元素,高度跟随父容器,宽度为父容器的一半,左侧的长方形将上和左的 border-radius设置为50%,使其显示为半圆,右侧的长方形同理,只是圆角的方向和左侧相反。这样,还只是两个长方形拼接而成的一个正方形,下一步为了让它显示为圆环,需要在父容器中再添加一个定位的元素,宽高设置取决于你想让圆环显示的宽度,将圆角设为50%,这样将它定位在父容器的水平和垂直居中位置,就实现了一个圆环。代码如下

<div class="circle">
    <div class="left" ref="circle_l"></div>
    <div class="right" ref="circle_r"></div>
    <div class="progress"><span class="score">{{total}}</span></div>
</div>
.circle {
  margin: 100px auto;
  position: relative;
  width: 128px;
  height: 128px;
}

.circle .progress {
  position: absolute;
  background-color: white;
  border-radius: 50%;
  text-align: center;
  width: 112px;
  height: 112px;
  top: 8px;
  left: 8px;
  line-height: 112px;
}
.circle .score {
  font-size: 46px;
  color: #007FFF;
}

.left,
.right {
  width: 64px;
  height: 128px;
  overflow: hidden;
  position: relative;
  float: left;
  background-color: #C4CFE3
}

.left {
  border-radius: 128px 0 0 128px;
}

.right {
  border-radius: 0 128px 128px 0;
}

下一步就要考虑如何显示具体的分数了,给左右两个元素各添加一个伪类,宽高与自身相同,同样设置圆角,通过 transform-origin 属性设置旋转元素的基点位置,左侧设置基点位置为 right 同理,右侧设置为 left,这样左右两个元素都与自身的伪类合成为一个正圆,如图

css代码中添加

.left:after,
.right:after {
    content: "";
    position: absolute;
    display: block;
    width: 64px;
    height: 128px;
    border-radius: 128px 0 0 128px;
    background-color: #007FFF;
}

.right:after {
    content: "";
    position: absolute;
    display: block;
    border-radius: 0 128px 128px 0;
}
.left:after {
    transform-origin: right center;
    transition: .4s;
    transform: rotateZ(40deg);
}

.right:after {
    transform-origin: left center;
    transform: rotateZ(180deg);
}

此时,设置 left::aftertransform属性为 rotateZ(40deg),已经初步有了效果

接下来将旋转的 deg 和分数结合起来。因为我们把整个圆分为左右两部分,写旋转的度数也是要分开考虑的,<=50分时只考虑改变 left::after 即可,>50分时,左侧默认为 0deg,剩下的只修改 right::after

因为整个圆被分割成100分,由此推导出

1分=3.6deg

左侧

旋转角度 = 180 - (已知分数×3.6)

例如:已知分数为40分,那旋转角度 = 180 - (40×3.6) = 36deg

右侧

旋转角度 = 180 - ((已知分数-50)×3.6)

例如:已知分数为70分,那旋转角度=180-((70-50)×3.6) = 108deg

光是这样推论、实践确实可以达到预期的效果了,但是!!!第一个坑来了,我使用vue来操作呀,那因为使用的伪类的方式来控制旋转角度,可以,获取伪类的方式还没用过,一查倒好,确实有!!

知识增加了!!!getComputedStyle(document.querySelector('.left'), ':after').getPropertyValue('transform') 这个是获取伪类中属性的写法。接下来是可以改变伪类属性的方法

document.styleSheets[0].addRule('.left::after',`transform: rotateZ(90deg);`)

亲测确实可用!!但是,放在vue里来使用就报错

我这“知难而退”的精神,考虑了一下,觉得这个不太适合用来做这个需求,要是就是固定的数值,不会变化的,一开始算好角度,写死在css里可能还可以,但这个看来还是不适用。虽然被pass掉了,但是也算是学习积累了,何况还学了一个获取和改变元素伪类属性的方法。。

那就接着找下一种方法,可是。。。这篇文章有点超长了。。。下一种方法还是在下一篇里再说趴o(╥﹏╥)o