最近业务上有了产品预约进度条的需求,故学习已有的一些成熟方案,便捷掌握使用方法
-
均分滚动条
首先是网易云音乐的用户等级进度条
经过一番搬运整理,我们也可以实现间隔均分段的滚动条,代码中的图像文件来自网易云音乐用户等级页面,感兴趣的读者可到官网上拿取。
以下为CSS样式
<style>
.sub {
width: 100%;
position: relative;
z-index: 1;
padding-top: 31px;
height: 34px;
overflow: hidden;
}
.sub .subbg {
width: 835px;
height: 10px;
position: absolute;
left: 0;
bottom: 0;
z-index: 2;
border-radius: 10px;
background: #dcdfe6;
}
.sub .subbg span {
/*一条渐变线*/
background: url(mylevelbar.png) 0 0 repeat-y;
width: 100%;
height: 10px;
display: block;
border-radius: 10px;
-webkit-animation: subbar 2s;
animation: subbar 2s;
}
.sub .subnum {
width: 100%;
height: 40px;
left: 0;
bottom: 0;
position: absolute;
z-index: 2;
}
.divison {
position: absolute;
left: 13px;
bottom: 0;
width: 100%;
height: 10px;
}
.divison span {
float: left;
display: inline;
width: 1px;
background: #fff;
height: 10px;
margin-left: 80px;
}
.divnum {
position: absolute;
left: -40px;
top: -20px;
font-family: 'Microsoft YaHei';
font-size: 18px;
color: #c4c6cc;
width: 980px;
}
.divnum li.z-ov {
color: #ed5757;
-webkit-animation: show 3s;
animation: show 3s;
}
.divnum li {
float: left;
width: 25px;
height: 28px;
line-height: 24px;
display: inline;
margin-right: 56px;
text-align: center;
}
li {list-style: none;}
.divnum li.z-on {
color: #fff;
-webkit-animation: show1 2s;
animation: show1 2s;
background-position: 0 -50px;
}
.h3 em,
.divnum li.z-on,
.n-pow .telist li,
.n-level i,
.n-level-big i {
/*此处的 0 -50px 和官网上的 0 9999px 有差异*/
background: url(mylevel.png) no-repeat 0 -50px;
}
/*动画效果*/
@keyframes subbar {
0% {
width: 0;
}
100% {
width: 100%;
}
}
@keyframes show {
0% {
color: #c4c6cc;
}
100% {
color: #ed5757;
}
}
@keyframes show1 {
0% {
color: #c4c6cc;
background-position: 9999px 9999px;
}
50% {
color: #c4c6cc;
background-position: 0 -50px;
}
100% {
color: #fff;
}
}
</style>
以下为HTML结构
<!-- 网易云音乐web版进度条 -->
<div class="sub">
<div class="subbg">
<!-- 通过js控制div的宽度实现进度条的进度,用动画控制前进效果 -->
<div style="width:820.8666666666667px;"><span></span></div>
<!-- /宽度为25+81x等级x70% -->
</div>
<div class="subnum">
<div class="divison"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></div>
<div class="divnum">
<ul>
<li class="z-ov">0</li>
<li class="z-ov">1</li>
<li class="z-ov">2</li>
<li class="z-ov">3</li>
<li class="z-ov">4</li>
<li class="z-ov">5</li>
<li class="z-ov">6</li>
<li class="z-ov">7</li>
<li class="z-ov">8</li>
<li class="z-on">9</li>
<li class="">10</li>
</ul>
</div>
<!-- / .ov已过等级样式 .on达到等级样式 -->
</div>
</div>
最终效果
看完了均匀进度的进度条,分享一下不均匀进度的进度条,一个移动端demo
-
不均分进度条
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>我的等级</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0,maximum-scale=1.0, user-scalable=0" />
<link rel="stylesheet" href="style.css">
<style id="dynamic"></style>
<script>
var Config = {
// 等级大图片url地址
courierRankBigUrl: 'images/grade3-icon.png',
// 配送员等级名称
courierRankName: '3级鲜锋官',
// 同时可接单数
courierCanPackgeCountDoing: '10',
// 积分数组1,2,3,4,5;50,100,150,200,250
integrationRankString: '1,2,3,4,5;0,100,150,200,250',
// 经验豆数组1,2,3,4,5;50,100,150,200,250
experienceBeanRankString: '',
// 本月累计积分
monthCompletedWaybills: '200'
};
</script>
<script>
function setStyle(obj,css){
for(var i in css){
obj.style[i] = css[i];
}
}
// 将积分数组切成两块,并用split方法转换成数组
var scores = Config.integrationRankString.split(";")[1].split(',');
console.log((Config.integrationRankString.split(";")[1]));
console.log( Config.integrationRankString.split(";")[1].split(',') instanceof Array);
// 后台返回的积分
var score = Config.monthCompletedWaybills;
/*
* 进度条的宽度百分比的计算方式设计如下:
* 假如第一段50分 第二段100分 第三段300分 第四段500分 那么假如服务器返回的是375分,那么在浏览器下占比如下
* 由于页面分了5段,每段显示20%的宽度; 遍历数组[50,100,300,500],定义一个遍历count = 0;
* 如果数组任何一段小于服务器返回375的话,那么count自加1,因此count=3
* 比例如下:(375 - 300) / (500 - 300) + 3 = 3/8 + 3 = 3.375; 最后 3.375 / 5 * 100%= 67.5%;
* 记住 因为数组arrs去掉了第一项了 所以curNum要减去1 即:curNum - 1
*/
/*
* @todo 计算进度条的百分比
* @param {score,arrs} 服务器返回的总分 服务器返回的数组
*/
var count = 0;
function percent(score,arrs) {
var tempCount = 0;
var percent;
// 如果积分大于数组最后一个总积分的话, 那么进度条就是最大的
if(score*1 > arrs[arrs.length -1] * 1) {
score = arrs[arrs.length -1];
}
for(var i = 0; i < arrs.length; i+=1) {
if(score*1 > arrs[i]*1) {
tempCount++;
}
}
count = tempCount;
if(tempCount*1 < 1) {
percent = (score / arrs[0]) / 5 * 100;
}else {
percent = ((score - arrs[tempCount - 1]) / (arrs[tempCount] - arrs[tempCount - 1]) + tempCount) / 5 * 100;
}
return percent + "%";
}
if(scores[0] == 0) {
scores.shift();
}
// 返回第五段的值 计算方法 val fiveVal = arrs[arrs.length - 1] * 2
var fiveVal = scores[scores.length - 1] * 2 + "";
scores.push(fiveVal);
var width = percent(score,scores);
var dynamic = document.getElementById("dynamic");
dynamic.innerHTML = '@-webkit-keyframes load {0% {width: 0%;}100% {width: '+width+';}}';
window.onload = function(){
var bar = document.getElementById("progress-bar");
setStyle(bar,{width:width});
}
</script>
</head>
<body>
<div class="myGrade-container">
<div class="myGrade-header">
<p class="grade-img" id="grade-img"></p>
<p class="grade-desc" id="courierRankName">二级鲜锋官</p>
<p class="grade-amount">可同时接单数<i id="grade-amount">2</i>单</p>
</div>
<div class="myGrade-progress-bar">
<h4>本月升级进度</h4>
<div class="myGrade-integral">
<div class="maGrade-wrap">
<h3 id="minMonthScore">本月累计积分<i id="monthScore">(97分)</i></h3>
<div class="progress-bar-inner">
<div class="progree-nums" id="progree-nums">
<!--
<span>1级</span>
<span>2级</span>
<span>3级</span>
<span>4级</span>
<span>5级</span>
-->
</div>
<div id="progress-box" class="progress-box">
<div class="division-bar" id="division-bar">
<span class="pbar w20"></span>
<span class="pbar w40"></span>
<span class="pbar w60"></span>
<span class="pbar w80"></span>
</div>
<div id="progress-bar" class="progress-bar">
</div>
<div></div>
</div>
<div class="progress-score" id="progress-score">
<!--
<i>0</i>
<span>50分</span>
<span>100分</span>
<span>300分</span>
<span>500分</span>
-->
</div>
</div>
</div>
</div>
</div>
<p class="myGrade-state">本月累计获得的积分决定下月的等级</p>
<ul class="myGrade-list">
<li id="show-grade">查看等级特权<i></i></li>
<li id="how-grade">如何提升等级<i></i></li>
</ul>
</div>
<script>
function $Id(id){
return document.getElementById(id);
};
function hasClass(obj, cls) {
return obj.className.match(new RegExp('(\\s|^)' + cls + '(\\s|$)'));
}
function addClass(obj, cls) {
if (!hasClass(obj, cls)) obj.className += " " + cls;
}
var bar = $Id("progress-bar"), // 进度条id
gradeImg = $Id("grade-img"), // 等级图片icon
courierRankName = $Id("courierRankName"), // 配送员等级名称
gradeAmount = $Id("grade-amount"), // 可同时接单数
monthScore = $Id("monthScore"), // 本月累计积分
scoreGrade = $Id("progree-nums"), // 等级id
progressScore = $Id("progress-score"), // 积分id
divisionBar = $Id("division-bar"); // 进度条分隔条
// 服务器返回的等级图片
gradeImg.style.backgroundImage="url("+Config.courierRankBigUrl+")";
// 服务器返回的等级名称
courierRankName.innerHTML = Config.courierRankName;
// 可同时接单数
gradeAmount.innerHTML = Config.courierCanPackgeCountDoing;
// 本月累计积分
monthScore.innerHTML = "(" + Config.monthCompletedWaybills + "分" + ")";
if(Config.monthCompletedWaybills *1 < 0) {
var minMonthScore = $Id("minMonthScore");
if(!hasClass(minMonthScore,'current')) {
addClass(minMonthScore,'current');
}
}
// 服务器返回的等级和积分数组
var grades = Config.integrationRankString.split(";")[0].split(','),
scores = Config.integrationRankString.split(";")[1].split(','),
gradesHTML = '';
scoresHTML = '';
for(var i = 0; i < grades.length; i++) {
gradesHTML += '<span>'+grades[i]+'级</span>';
}
scoreGrade.innerHTML = gradesHTML;
for(var j = 0; j < scores.length; j++) {
if(j == 0) {
scoresHTML += '<i>'+scores[j]+'</i>';
}else {
scoresHTML += '<span>'+scores[j]+'分</span>';
}
}
progressScore.innerHTML = scoresHTML;
var divisionBarSpans = divisionBar.getElementsByTagName("span");
// 后台返回的积分
var score2 = Config.monthCompletedWaybills;
var curIndex = scores.indexOf(score2);
if(count*1 > 0) {
for(var i = 0; i < count; i++) {
if(!hasClass(divisionBarSpans[i],'current')) {
// 比如返回积分是200 正好数组也有200这个积分 正好相等的话 ,那么就不添加current类名
if(i !== curIndex) {
(function(i){
setTimeout(function(){
addClass(divisionBarSpans[i],'current');
},2500);
})(i)
}
}
}
}
</script>
</body>
</html>
css 样式
// css reset
body,h1,h2,h3,h4,h5,h6,hr,p,blockquote,dl,dt,dd,ul,ol,li,pre,form,fieldset,legend,button,input,textarea,th,td{margin:0;padding:0;font-family:"Microsoft yahei";color:#000;}
ul,ol,li{list-style:none;}
i,em{font-style:normal}
img{max-width:100%;}
html{font-size:62.5%;}
html,body{background:#f5f5f5;}
.myGrade-container {width:100%;background:#f5f5f5;}
.myGrade-header {width:100%;margin-top:20px;border-top:1px solid #d7d7d7;border-bottom:1px solid #d7d7d7;text-align:center;background:#fff;padding:18px 0 20px 0;}
.grade-img {background-repeat:no-repeat;background-size:66px 66px;width:66px;height:66px;margin:0 auto;}
.grade-desc {padding:12px 0;color:#fc6605;}
.grade-amount {font-size:1em;font-family:"Microsoft yahei";}
.grade-amount i{padding-left:4px;}
.myGrade-progress-bar {width:100%;}
.myGrade-progress-bar h4{color:#707070;font-size:1.125em;font-weight:500;padding-left:10px;padding-top:30px;}
.myGrade-integral {border-top:1px solid #d8d7d8;border-bottom:1px solid #d8d7d8;background:#fff;margin-top:8px;}
.maGrade-wrap {width:90%;margin:0 auto;padding-bottom:20px;}
.myGrade-integral h3{font-size:1.125em;font-weight:500;padding:16px 0;}
.myGrade-integral h3 i{color:#81bb3b;}
.progress-bar-inner {position:relative;}
.progree-nums {width:100%;font-size:0;overflow:hidden;}
.progree-nums span,.progress-score span{float:left;display:inline-block;width:20%;text-align:center;color:#757575;}
.progress-box{position:relative;height:16px;border:1px solid #a0db58;border-radius:30px;margin-top:5px;}
.progress-bar{position:absolute;left:0;top:0;height:16px;background:#a0db58;border-radius:30px;z-index:9;}
.division-bar {position:absolute;left:0;top:0;width:100%;z-index:11;}
.division-bar .pbar {position:absolute;height:16px;background-color:#a0db58;left:20%;width:1px;}
.division-bar .w20 {left:20%;}
.division-bar .w40 {left:40%;}
.division-bar .w60 {left:60%;}
.division-bar .w80 {left:80%;}
.progress-score {position:relative;margin-top:5px;font-size:0;overflow:hidden;}
.progress-score span{text-align:right;}
.progress-score i{position:absolute;left:0;top:0;color:#757575;}
.myGrade-state {width:95%;height:50px;padding-left:5%;margin-top:15px;background:#f5f5f5;color:#707070;border-bottom:1px solid #d8d7d8;}
.myGrade-list li{width:95%;padding-left:5%;background:#fff;border-bottom:1px solid #d8d7d8;height:60px;line-height:60px;}
.myGrade-list li i{float:right;padding-right:4%;background:url("images/arrow.png") no-repeat;width:10px;height:17px;background-size:10px 17px;margin-top:22px;}
/* 当前加粗 */
.progree-nums span.current{font-weight:700;color:#212121;}
.division-bar span.current{background-color:#fff;}
.myGrade-integral h3.current,.myGrade-integral h3.current i{color:#f44336;}
/* 媒体查询 */
.grade-desc{font-size:1.8rem;}
.grade-amount{font-size:1.6rem;}
.myGrade-progress-bar h4{font-size:1.5rem;}
.myGrade-integral h3{font-size:1.6rem;}
.progree-nums span,.progress-score span{font-size:1.5rem;}
.myGrade-state {font-size:1.5rem;}
.myGrade-list li {font-size:1.8rem;}
.progress-score i{font-size:1.5rem;}
@media (min-width:360px) and (max-width: 399px) {
}
@media (min-width: 320px) and (max-width:359px){
.progress-score i,.progress-score span{font-size:1.3rem;}
}
.progress-bar {background:-webkit-gradient(linear, 0 0, 0 100%,from(#a0db58),to(#a0db58));-webkit-animation: load 3s ease-out 1;}
完成效果
移动端的demo来自网络,这个demo涉及到了进度条的动态实现,代码比较长比较复杂,实现不均匀进度。