前两天偶然看到这个题目,抽空做了一下
话不多说,看看具体怎么实现的叭
如果是对其前端比较熟悉的人,看到这个图应该大致知道有哪几个点啦,比如用到了同心圆、旋转。
1.画两种不同背景色的圆(我这里是旋转的浅色,把深色作为底色,在浅色旋转的过程中,深色一步步露出来)
2.浅色部分是两个圆切割出的两个半圆,一个左半圆,一个右半圆
3.右半圆旋转180°后,置它的背景色为底色,位置归位
4.然后左半圆旋转,180°后停止
5.中间是用一个小一点的白色背景圆遮住形成圆的效果,数字用定时器模拟0-100的变化
以上需要注意的是,旋转度数是根据中间的数字*360°计算的,由于左半圆开始旋转时中间数字已经为50%,故左半圆的旋转度数还要减去180°。
几个用到的CSS属性:
border-radius
--画圆
transform:rotate(xdeg)
--旋转
clip:rect(top,right,bottom,left)
--切割半圆
先看html代码
<!-- 最外面是深色圆 -->
<div class="circle-bar">
<!-- 里面两个是两个半圆 -->
<div class="left-circle-bar"></div>
<div class="right-circle-bar"></div>
<!-- 然后是中间白色部分 -->
<div class="mask">
<span>0%</span>
</div>
</div>
css代码
/* 画圆 */
.circle-bar, .circle-bar > * {
border-radius: 50%;
}
/* 实现同心圆,也就是让所有子元素都有一样的绝对定位 */
.circle-bar > *{
position: absolute;
top:0;
left: 0;
right: 0;
bottom: 0;
margin: auto;
}
/* 用font-size可以让容器与子元素的宽高用相对单位em,这样只要改变font-size大小,整个形状都能改变*/
.circle-bar{
font-size: 200px;
height: 1em;
width: 1em;
background-color:rgb(221, 42, 42);
position: relative;
}
.left-circle-bar,.right-circle-bar{
height:1em;
width:1em;
background-color: lightcoral;
}
/*切割半圆*/
.left-circle-bar{
clip: rect(0,0.5em,1em,0);
}
.right-circle-bar{
clip: rect(0,1em,1em,0.5em);
}
/*白色部分,用了flex布局使百分比垂直居中显示*/
.circle-bar .mask{
height:0.8em;
width: 0.8em;
background-color: white;
display: flex;
justify-content: center;
align-items: center;
}
.circle-bar .mask span{
font-size: 0.25em;
}
以上就是实现了静态的页面,看起来是这样
然后要做的就是百分比模拟0-100变化,半圆的旋转与中间的百分比进行绑定,这里有两个注意点:
1.监控中间span元素的变化
onchange
事件监听只能作用于input text
等输入框,而普通的文本元素如何监听呢,我们有DOMNodeInserted
,那么怎样的文本变化形式可以触发这个事件呢?
使用DOMElement.innerHTML = '50%'
方法改变的span内容可以触发DOMNodeInserted
使用DOMElement.innerText= '50%'
方法改变的span内容不可以触发DOMNodeInserted
2.获取底层圆的背景色
在前面我们说到,当旋转过一半时,右半圆的背景色要置为与底色一样的,那么如何获取这个非内联样式的背景色呢
直接使用DOMElement.style.backgroundColor
是获取不到的,因为它只能获取内联样式。
在DOM标准中有一个全局方法window.getComputedStyle(DOMElement,null).
,但是它不兼容IE,IE中的DOM元素属性有一个方法DOMElement.currentStyle.
,本文中没有对这两种进行封装,大家可以自己封装一下,做起来也很简单
那么我们看最后的js代码
let spanEle = document.querySelector("span");
let leftCircle = document.querySelector(".left-circle-bar");
let rightCircle = document.querySelector(".right-circle-bar");
let circle= document.querySelector(".circle-bar");
//获取底圆的背景色
let color = window.getComputedStyle(circle).backgroundColor;
//这里模拟span元素值得变化
//顺便说一下,innerHTML和innertext的区别,前者是W3C的标准属性,后者兼容性不强,前者包括标签,后者只显示内容
let interval = setInterval(() => {
let num = parseInt(spanEle.innerHTML);
if(num<100){
num++;
}else{
num = 100;
clearInterval(interval);
}
spanEle.innerHTML = num +'%' ;
}, 100);
spanEle.addEventListener('DOMNodeInserted',function(e){
//当span元素中的值发生变化则改变圆环的旋转度数
let num = parseInt(e.target.nodeValue);
// console.log(num);
let deg;
if(num<=50){
deg = num*3.6 + 'deg';
rightCircle.style["transform"] = 'rotate('+ deg + ')';
}else{
//因为旋转度数过半,这里对num减去了50,然后再用结果乘度数
deg = (num-50)*3.6 + 'deg';
leftCircle.style["transform"] = 'rotate('+ deg + ')';
rightCircle.style.backgroundColor = color;
rightCircle.style["transform"] = 'rotate(0deg)';
}
});
这样就结束啦,一个环形进度条就实现完毕啦