JS 倒计时展示小工具
废话开篇:JS 通过操控标签的隐藏与显示来实现倒计时展示小工具
一、实现效果
1、默认展示数字
2、数字倒计时
3、数字倒计时展示虚位
4、数字倒计时不展示虚位
每一个单独数字都是由一个独立的标签进行的绘制,再通过数字的处理将独立数字组合成一个完整的数字展示。
二、代码
1、HTML
<div class="numer_wsl_contain">
<div id="number1"></div>
<div id="number2"></div>
<div id="number3"></div>
<div id="number4"></div>
</div>
<script>
let wholeNumberManage1 = new WholeNumberManage(21921,document.getElementById('number1'),1000)
let wholeNumberManage2 = new WholeNumberManage(21921,document.getElementById('number2'),1000)
wholeNumberManage2.isCountDown = true
let wholeNumberManage3 = new WholeNumberManage(1021,document.getElementById('number3'),50)
wholeNumberManage3.isCountDown = true
let wholeNumberManage4 = new WholeNumberManage(1021,document.getElementById('number4'),50)
wholeNumberManage4.isCountDown = true
wholeNumberManage4.isShowVirtualNum = false
</script>
大部分的布局操作全部放到 JS 里,简化 html 内容。
2、CSS
.numer_wsl_contain{
width: 100%;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
.number_wsl {
margin-top: 50px;
width: 100%;
position: relative;
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
}
.num_wsl {
position: relative;
width: 23px;
height: 30px;
}
/* 绘制横杠 */
.num_wsl_cross {
position: absolute;
left: 0px;
width: 100%;
height: 10%;
background:
linear-gradient(135deg,transparent 0, transparent 50%,black 50%,black 100%),
linear-gradient(45deg,transparent 0, transparent 50%,black 50%,black 100%),
linear-gradient(-135deg,transparent 0, transparent 50%,black 50%,black 100%),
linear-gradient(-45deg,transparent 0, transparent 50%,black 50%,black 100%);
background-repeat: no-repeat;
background-position:
0% 0%,
0% 100%,
100% 0%,
100% 100%;
background-size:
50% 50%,
50% 50%,
50% 50%,
50% 50%;
}
/* 3个横杠位置区分 */
.num_wsl_cross_one {
top: 0px;
}
.num_wsl_cross_two {
top: 45%;
}
.num_wsl_cross_three {
top: 90%;
}
/* 绘制竖杠 */
.num_wsl_vertical {
position: absolute;
top: -5%;
width: 12%;
height: 65%;
background:
linear-gradient(135deg,transparent 0, transparent 50%,black 50%,black 100%),
linear-gradient(45deg,transparent 0, transparent 50%,black 50%,black 100%),
linear-gradient(-135deg,transparent 0, transparent 50%,black 50%,black 100%),
linear-gradient(-45deg,transparent 0, transparent 50%,black 50%,black 100%);
background-repeat: no-repeat;
background-position:
0% 0%,
0% 100%,
100% 0%,
100% 100%;
background-size:
50% 50%,
50% 50%,
50% 50%,
50% 50%;
}
/* 6个绘制竖杠位置区分 */
.num_wsl_vertical_one {
left: 16.2%;
}
.num_wsl_vertical_two {
left: 72.8%;
}
.num_wsl_vertical_three {
top: 40.8%;
left: 16.2%;
}
.num_wsl_vertical_four {
top: 40.8%;
left: 72.8%;
}
3、数字管理类
NumberSingleManage 单数字展示类
// 单数字操作
class NumberSingleManage {
// 操作dom对象
el = null
map = {}
// 当前数字
_num = 0
constructor(num,el){
if(el){
this.el = el
} else {
// 没有dom传入对象,进行创建
this.el = this.createElement(['num_wsl'])
}
// 创建单数字节点(3横,4竖)
this.createSingleNumNode()
this.getSingleMapRelationship()
this.overwriteSetMethod()
this.num = num
}
// 重写set方法
overwriteSetMethod(){
Object.defineProperty(this, 'num', {
get: function () {
return this._num
},
set: function (newValue) {
this._num = newValue
this.changeNum(this._num)
}
})
}
// 创建单数字节点
createSingleNumNode(){
//样式集合
let classes = [
['num_wsl_cross','num_wsl_cross_one'],
['num_wsl_cross','num_wsl_cross_two'],
['num_wsl_cross','num_wsl_cross_three'],
['num_wsl_vertical','num_wsl_vertical_one'],
['num_wsl_vertical','num_wsl_vertical_two'],
['num_wsl_vertical','num_wsl_vertical_three'],
['num_wsl_vertical','num_wsl_vertical_four']
]
//添加节点
classes.forEach(classNames => {
this.el.appendChild(this.createElement(classNames))
});
}
// 创建el并赋予样式
createElement(classNames){
let div = document.createElement('div')
classNames.forEach((className)=>{
div.classList.add(className)
})
return div
}
// 建立映射关系(数字对应数字节点的隐藏与显示)
getSingleMapRelationship(){
let num_cross_one = this.el.getElementsByClassName('num_wsl_cross_one')[0]
let num_cross_two = this.el.getElementsByClassName('num_wsl_cross_two')[0]
let num_cross_three = this.el.getElementsByClassName('num_wsl_cross_three')[0]
let num_vertical_one = this.el.getElementsByClassName('num_wsl_vertical_one')[0]
let num_vertical_two = this.el.getElementsByClassName('num_wsl_vertical_two')[0]
let num_vertical_three = this.el.getElementsByClassName('num_wsl_vertical_three')[0]
let num_vertical_four = this.el.getElementsByClassName('num_wsl_vertical_four')[0]
this.map = {
reset:()=>{
this.elShow(num_cross_one)
this.elShow(num_cross_two)
this.elShow(num_cross_three)
this.elShow(num_vertical_one)
this.elShow(num_vertical_two)
this.elShow(num_vertical_three)
this.elShow(num_vertical_four)
},
0:()=>{
this.elShow(num_cross_one)
this.elHide(num_cross_two)
this.elShow(num_cross_three)
this.elShow(num_vertical_one)
this.elShow(num_vertical_two)
this.elShow(num_vertical_three)
this.elShow(num_vertical_four)
},
1:()=>{
this.elHide(num_cross_one)
this.elHide(num_cross_two)
this.elHide(num_cross_three)
this.elHide(num_vertical_one)
this.elShow(num_vertical_two)
this.elHide(num_vertical_three)
this.elShow(num_vertical_four)
},
2:()=>{
this.elShow(num_cross_one)
this.elShow(num_cross_two)
this.elShow(num_cross_three)
this.elHide(num_vertical_one)
this.elShow(num_vertical_two)
this.elShow(num_vertical_three)
this.elHide(num_vertical_four)
},
3:()=>{
this.elShow(num_cross_one)
this.elShow(num_cross_two)
this.elShow(num_cross_three)
this.elHide(num_vertical_one)
this.elShow(num_vertical_two)
this.elHide(num_vertical_three)
this.elShow(num_vertical_four)
},
4:()=>{
this.elHide(num_cross_one)
this.elShow(num_cross_two)
this.elHide(num_cross_three)
this.elShow(num_vertical_one)
this.elShow(num_vertical_two)
this.elHide(num_vertical_three)
this.elShow(num_vertical_four)
},
5:()=>{
this.elShow(num_cross_one)
this.elShow(num_cross_two)
this.elShow(num_cross_three)
this.elShow(num_vertical_one)
this.elHide(num_vertical_two)
this.elHide(num_vertical_three)
this.elShow(num_vertical_four)
},
6:()=>{
this.elShow(num_cross_one)
this.elShow(num_cross_two)
this.elShow(num_cross_three)
this.elShow(num_vertical_one)
this.elHide(num_vertical_two)
this.elShow(num_vertical_three)
this.elShow(num_vertical_four)
},
7:()=>{
this.elShow(num_cross_one)
this.elHide(num_cross_two)
this.elHide(num_cross_three)
this.elHide(num_vertical_one)
this.elShow(num_vertical_two)
this.elHide(num_vertical_three)
this.elShow(num_vertical_four)
},
8:()=>{
this.elShow(num_cross_one)
this.elShow(num_cross_two)
this.elShow(num_cross_three)
this.elShow(num_vertical_one)
this.elShow(num_vertical_two)
this.elShow(num_vertical_three)
this.elShow(num_vertical_four)
},
9:()=>{
this.elShow(num_cross_one)
this.elShow(num_cross_two)
this.elShow(num_cross_three)
this.elShow(num_vertical_one)
this.elShow(num_vertical_two)
this.elHide(num_vertical_three)
this.elShow(num_vertical_four)
}
}
}
//显示全部节点
showAllNode(){
this.map['reset']()
}
//变更数字
changeNum(num){
this.map[num] && this.map[num]()
}
//显示
elShow(el){
el.style.visibility="visible"
}
//隐藏
elHide(el){
el.style.visibility="hidden"
}
}
WholeNumberManage 完整数字展示与操作类
// 整串数字操作
class WholeNumberManage {
//单数字存储
numberSingleManages = []
//完整数字
wholeNum = null
//展示的dom对象
mountedEl = null
//定时器
timer = null
//是否显示虚位
isShowVirtualNum = true
//是否开始倒计时
_isCountDown = null
//倒计时时间间隔
_countDownInterval = 1000
constructor(wholeNum,el,countDownInterval){
this.mountedEl = el
this.mountedEl.classList.add("number_wsl")
this.wholeNum = wholeNum
this._countDownInterval = countDownInterval
//创建并展示完整的数字,通过单数字对象
this.createWholeNumShowEl(this.parseWholeNum(wholeNum))
//重写set方法,控制是否开始倒计时
this.overwriteSetMethod()
}
// 重写set方法
overwriteSetMethod(){
// 是否进行倒计时
Object.defineProperty(this, 'isCountDown', {
get: function () {
return this._isCountDown
},
set: function (newValue) {
if(newValue){
this._isCountDown = newValue
this.startCountDown()
} else {
clearInterval(this.timer)
}
}
})
}
// 倒计时
startCountDown(){
if(!this.wholeNum || this.wholeNum <= 0){
return
}
if(this.timer){
clearInterval(this.timer)
}
this.timer = setInterval(()=>{
if(this.wholeNum < 0){
clearInterval(this.timer)
}
this.wholeNum -= 1
//刷新倒计时数字
this.countDownRefreshNum(this.parseWholeNum(this.wholeNum))
},this._countDownInterval)
}
// 解析数字
parseWholeNum(wholeNum){
//整数操作
if(String(wholeNum).indexOf('.') == -1){
return this.parseWholeIntegralNum(wholeNum)
}
return null
}
// 整型数字解析
parseWholeIntegralNum(wholeNum){
let nums = []
if(wholeNum != 0){
//截取各个位上的数字
while(wholeNum != 0){
nums.push(wholeNum % 10)
wholeNum = (wholeNum - nums.slice(-1)[0]) / 10
}
} else {
nums = [0]
}
return nums.reverse()
}
// 创建数字展示区
createWholeNumShowEl(nums){
nums.forEach((num)=>{
this.numberSingleManages.push(new NumberSingleManage(num))
if(this.mountedEl){
this.mountedEl.appendChild(this.numberSingleManages.slice(-1)[0].el)
}
})
}
// 刷新数字
countDownRefreshNum(nums){
//展示虚位
if(this.isShowVirtualNum){
//全部重置为0
this.numberSingleManages.forEach((numberSingleManage)=>{
numberSingleManage.num = 0
})
//数字进行填充
nums.forEach((num,index)=>{
this.numberSingleManages[(this.numberSingleManages.length - nums.length) + index].num = num
})
} else {
//不展示虚位
let virtualNum = this.numberSingleManages.length - nums.length;
//清除前面虚位并移除dom
if(virtualNum != 0){
let needMoveNumberSingleManages = this.numberSingleManages.splice(0,virtualNum)
needMoveNumberSingleManages.forEach((numberSingleManages)=>{
numberSingleManages.el.remove()
})
}
//数字进行填充
nums.forEach((num,index)=>{
this.numberSingleManages[index].num = num
})
}
}
}
三、总结与思考
其实就是单纯的dom操作,没有特别难理解的内容。代码拙劣,大神勿笑[抱拳][抱拳][抱拳]
转载自:https://juejin.cn/post/7195453433179504700