- 作者:陈大鱼头
- github: KRISACHAN
进度条是一个十分常见的性能,实现起来也不难,个别咱们都会用 div
来实现。
作为一个这么常见的需要, whatwg 必定是不会没有原生组件提供(尽管有咱们也不肯定会用),那么就让咱们来康康有哪些有意思的进度条实现形式。
惯例版 — div 一波流
这是比拟惯例的实现形式,先看成果:
源码如下:
<style> .progress1 { height: 20px; width: 300px; background-color: #f5f5f5; border-bottom-right-radius: 10px; border-top-right-radius: 10px; } .progress1::before { counter-reset: progress var(--percent, 0); content: counter(progress) '%\2002'; display: block; height: 20px; line-height: 20px; width: calc(300px * var(--percent, 0) / 100); font-size: 12px; color: #fff; background-color: #2486ff; text-align: right; white-space: nowrap; overflow: hidden; border-bottom-right-radius: 10px; border-top-right-radius: 10px; } .btn { margin-top: 30px; }</style><div id="progress1" class="progress1"></div><button id="btn" class="btn">点我一下嘛~</button><script> 'use strict'; let startTimestamp = (new Date()).getTime(); let currentPercentage = 0; let maxPercentage = 100; let countDelay = 100; let timer = null; let start = false; const percentageChange = () => { const currentTimestamp = (new Date()).getTime(); if (currentTimestamp - startTimestamp >= countDelay) { currentPercentage++; startTimestamp = (new Date()).getTime(); progress1.style = `--percent: ${currentPercentage}`; }; if (currentPercentage < maxPercentage) { timer = window.requestAnimationFrame(percentageChange); } else { window.cancelAnimationFrame(timer); }; }; const clickHander = () => { if (!start) { start = true; percentageChange(); }; }; btn.addEventListener('click', clickHander);</script>
这种办法的外围就是以以后盒子为容器,以 ::before
为内容填充。用 <div>
的益处就是实现简略,兼容性强,拓展性高,然而美中不足的是标签语义化不强。
进阶版 — input type="range"
<input />
是一个十分实用的替换元素,不同的 type 能够做不同的事件。第二种就是用 <input type="range" />
来实现的。首先咱们来看看成果:
源码如下:
<style> .progress2[type='range'] { display: block; font: inherit; height: 20px; width: 300px; pointer-events: none; background-color: linear-gradient(to right, #2376b7 100%, #FFF 0%); } .progress2[type='range'], .progress2[type='range']::-webkit-slider-thumb { -webkit-appearance: none; }; .progress2[type='range']::-webkit-slider-runnable-track { border: none; border-bottom-right-radius: 10px; border-top-right-radius: 10px; height: 20px; width: 300px; } .btn { margin-top: 30px; }</style><input id="progress2" class="progress2" type='range' step="1" min="0" max="100" value="0"/><button id="btn" class="btn">点我一下嘛~</button><script> 'use strict'; let startTimestamp = (new Date()).getTime(); let currentPercentage = 0; let maxPercentage = 100; let countDelay = 100; let timer = null; let start = false; let percentageGap = 10; const percentageChange = () => { const currentTimestamp = (new Date()).getTime(); if (currentTimestamp - startTimestamp >= countDelay) { currentPercentage++; startTimestamp = (new Date()).getTime(); progress2.value = currentPercentage; progress2.style.background = `linear-gradient(to right, #2376b7 ${currentPercentage}%, #FFF 0%`; }; if (currentPercentage < maxPercentage) { timer = window.requestAnimationFrame(percentageChange); } else { window.cancelAnimationFrame(timer); }; }; const clickHander = () => { if (!start) { start = true; percentageChange(); }; }; btn.addEventListener('click', clickHander);</script>
写完这个 demo 才发现,<input type="range" />
并不适宜做这个性能。。一个是实现艰难,这个 type 组件的每个元件都能够独自批改款式,然而成果并不是很好。
另一个是因为 range 有专属语意 —— 范畴,所以它更适宜做上面这种事:
以上demo来自:https://developer.mozilla.org...
高级版 — progress 鸭
当然,上述两种形式都是模仿进度条,实际上咱们并不需要模仿,因为 whatwg 有为咱们提供原生的进度条标签 —— <progress>
。
咱们先看成果:
实现如下:
<style> .progress3 { height: 20px; width: 300px; -webkit-appearance: none; display: block; } .progress3::-webkit-progress-value { background: linear-gradient( -45deg, transparent 33%, rgba(0, 0, 0, .1) 33%, rgba(0,0, 0, .1) 66%, transparent 66% ), linear-gradient( to top, rgba(255, 255, 255, .25), rgba(0, 0, 0, .25) ), linear-gradient( to left, #09c, #f44); border-radius: 2px; background-size: 35px 20px, 100% 100%, 100% 100%; } .btn { margin-top: 30px; }</style><progress id="progress3" class="progress3" max="100" value="0"></progress><button id="btn" class="btn">点我一下嘛~</button><script> 'use strict'; let startTimestamp = (new Date()).getTime(); let currentPercentage = 0; let maxPercentage = 100; let countDelay = 100; let timer = null; let start = false; const percentageChange = () => { const currentTimestamp = (new Date()).getTime(); if (currentTimestamp - startTimestamp >= countDelay) { currentPercentage++; startTimestamp = (new Date()).getTime(); progress3.setAttribute('value', currentPercentage); }; if (currentPercentage < maxPercentage) { timer = window.requestAnimationFrame(percentageChange); } else { window.cancelAnimationFrame(timer); }; }; const clickHander = () => { if (!start) { start = true; percentageChange(); }; }; btn.addEventListener('click', clickHander);</script>
尽管有原生的进度条标签,然而标准里并没有规定它的具体表现,所以各个浏览器厂商齐全能够依照本人的爱好去定制,款式齐全不可控,所以标签虽好。。可用性却不强,有点惋惜。
终极版 — meter 赛高
当然,可能实现进度条性能的标签,除了下面所说的,还有 <meter>
标签。先看成果:
代码如下:
<style> .progress4 { display: block; font: inherit; height: 50px; width: 300px; pointer-events: none; } .btn { margin-top: 30px; }</style><meter id="progress4" class="progress4" low="60" high="80" min="0" max="100" value="0"></meter><button id="btn" class="btn">点我一下嘛~</button><script> 'use strict'; let startTimestamp = (new Date()).getTime(); let currentPercentage = 0; let maxPercentage = 100; let countDelay = 100; let timer = null; let start = false; const percentageChange = () => { const currentTimestamp = (new Date()).getTime(); if (currentTimestamp - startTimestamp >= countDelay) { currentPercentage++; startTimestamp = (new Date()).getTime(); progress4.value = currentPercentage; }; if (currentPercentage < maxPercentage) { timer = window.requestAnimationFrame(percentageChange); } else { window.cancelAnimationFrame(timer); }; }; const clickHander = () => { if (!start) { start = true; percentageChange(); }; }; btn.addEventListener('click', clickHander);</script>
这个标签可能比拟生疏,实际上它跟 <input type="range">
的语义是一样的,用来显示已知范畴的标量值或者分数值。不一样的就是。。。它款式改起来更麻烦。
总结
本文测评了4种实现进度条的形式,得出的论断就是 —— <div>
赛高。。。尽管有的时候想优雅一点谋求标签语义化,然而资源不反对,也很难堪。
嗯,万能的 <div>
。
以上 demo 都能够我的 codepen 上查看:https://codepen.io/krischan77...