Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 89 additions & 0 deletions 29 - Countdown Timer/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
# 29 Countdown Timer 中文指南

> 本篇作者:©[大史快跑Dashrun](https://github.com/dashrun)——Chinasoft Frontend Developer

> 简介:[JavaScript30](https://javascript30.com) 是 [Wes Bos](https://github.com/wesbos) 推出的一个 30 天挑战。项目免费提供了 30 个视频教程、30 个挑战的起始文档和 30 个挑战解决方案源代码。目的是帮助人们用纯 JavaScript 来写东西,不借助框架和库,也不使用编译器和引用。现在你看到的是这系列指南的第 29 篇。完整指南在 [GitHub](https://github.com/soyaine/JavaScript30),喜欢请 Star 哦♪(^∇^*)

> 创建时间:2017-11-6
最后更新:2017-11-12

## 挑战任务
初始文档`index-start.html`中提供了一个倒计时控制器,从`html`文档的结构可以看出,顶部的按钮可以用来增加倒计时时间,常用的时间间隔已将参数绑定在`data-time`属性上;`display`类用来显示计时的结果。
本次编程挑战的任务是通过javascript代码基于当前时间生成一个倒计时,将`结束时间`和`剩余时间`分别显示在`diaplay__time-left`类标签和`display__end-time`类标签上。

## 实现效果
![结果展示](https://github.com/dashrun/vanilla-javascript-30/blob/master/29%20-%20Countdown%20Timer/effect.png)

## 编程思路
监听按点击事件`click`来为倒计时增加时间,使用`setInterval`函数每秒执行判断函数,若倒计时事件到,则清除当前计时器,若时间未到,则计算并刷新页面上应该显示的时间。

## 过程指南
1.定义变量及获取需要操作的DOM元素的引用。
```js
const endTime = document.querySelector(".display__end-time");
const leftTime = document.querySelector(".display__time-left");
const buttons = document.querySelectorAll("button");
const date = new Date();
var left = 0;//剩余时间
var end = 0;//结束时间
var timer;//interval计时器
leftTime.innerHTML = left;//未操作时,剩余时间显示0
```
2.为button绑定点击事件,当按钮点击时执行对应的回调函数。
```js
const arr = Array.from(buttons);
arr.map(function(item){
item.addEventListener('click',clickAction);
});
```
3.监听表单的提交事件,注意表单的调用方式。
```js
document.customForm.addEventListener('submit',function(e){
e.preventDefault();
updateTime(this.minutes.value*60);
updateTimer();
});
```
4.点击后的回调函数中取得点击按钮传递的秒数,调用`updateTime()`函数更新页面显示结果,并调用`updateTimer()`来更新计时器相关动作.
```js
function clickAction(e){
let deltaTime;
deltaTime = this.dataset.time;//取得data-time属性的值
updateTime(deltaTime);

//点击后更新计时器
updateTimer();
}
```
5.`updateTime()`函数用来更新和页面相关的显示信息。
```js
function updateTime(delta){
left = left + parseInt(delta,0);
end = date.getTime() + left*1000;
leftTime.innerHTML = left;
endTime.innerHTML =new Date(end).toLocaleTimeString();
}
```
6.`updateTimer()`函数用来执行和设定每秒检查计时器是否需要继续工作的逻辑判断。
```js
function updateTimer(){
//清除以前的timer,如果不清除,新生成的定时器会和以前的定时器叠加在一起,均会生效。
if(timer){
clearInterval(timer);
}

// 设置新的Timer
timer = setInterval(function(){
if(left == 0){
endTime.innerHTML = 'End';
clearInterval(timer);
}else{
left -= 1;
leftTime.innerHTML = left;
}
},1000);
}
```

## 延伸思考
本次代码中前后会定义定时器和清除定时器,另一种做法是定时器一直工作不清除,对应的按钮和表单只修改时间,不用调整定时器,当值发生变化后,下一秒定时器检测时就会开始倒计时,这样代码逻辑上会有所简化,感兴趣的朋友可以自行练习。
Binary file added 29 - Countdown Timer/effect.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
29 changes: 29 additions & 0 deletions 29 - Countdown Timer/index-start.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Countdown Timer</title>
<link href='https://fonts.googleapis.com/css?family=Inconsolata' rel='stylesheet' type='text/css'>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="timer">
<div class="timer__controls">
<button data-time="20" class="timer__button">20 Secs</button>
<button data-time="300" class="timer__button">Work 5</button>
<button data-time="900" class="timer__button">Quick 15</button>
<button data-time="1200" class="timer__button">Snack 20</button>
<button data-time="3600" class="timer__button">Lunch Break</button>
<form name="customForm" id="custom">
<input type="text" name="minutes" placeholder="Enter Minutes">
</form>
</div>
<div class="display">
<h1 class="display__time-left"></h1>
<p class="display__end-time"></p>
</div>
</div>

<script src="scripts-START.js"></script>
</body>
</html>
61 changes: 61 additions & 0 deletions 29 - Countdown Timer/scripts-START.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
const endTime = document.querySelector(".display__end-time");
const leftTime = document.querySelector(".display__time-left");
const buttons = document.querySelectorAll("button");
const date = new Date();
var left = 0;//剩余时间
var end = 0;//结束时间
var timer;//interval计时器
leftTime.innerHTML = left;//未操作时,剩余时间显示0

//为button绑定点击事件
const arr = Array.from(buttons);
arr.map(function(item){
item.addEventListener('click',clickAction);
});

//监听自定义输入
document.customForm.addEventListener('submit',function(e){
e.preventDefault();
updateTime(this.minutes.value*60);
updateTimer();
});

//定义点击后的回调
function clickAction(e){
let deltaTime;
deltaTime = this.dataset.time;
updateTime(deltaTime);

//点击后更新计时器
updateTimer();
}



//updateTime
function updateTime(delta){
left = left + parseInt(delta,0);
end = date.getTime() + left*1000;
leftTime.innerHTML = left;
endTime.innerHTML =new Date(end).toLocaleTimeString();
}

//每秒刷新时间
function updateTimer(){
//清除以前的timer
if(timer){
clearInterval(timer);
}

// 设置新的Timer
timer = setInterval(function(){
if(left == 0){
endTime.innerHTML = 'End';
clearInterval(timer);
}else{
left -= 1;
leftTime.innerHTML = left;
}
},1000);
}

82 changes: 82 additions & 0 deletions 29 - Countdown Timer/style.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
html {
box-sizing: border-box;
font-size: 10px;
background: #8E24AA;
background: linear-gradient(45deg, #42a5f5 0%,#478ed1 50%,#0d47a1 100%);
}

*, *:before, *:after {
box-sizing: inherit;
}

body {
margin:0;
text-align: center;
font-family: 'Inconsolata', monospace;
}

.display__time-left {
font-weight: 100;
font-size: 20rem;
margin: 0;
color:white;
text-shadow:4px 4px 0 rgba(0,0,0,0.05);
}

.timer {
display:flex;
min-height: 100vh;
flex-direction:column;
}

.timer__controls {
display: flex;
}

.timer__controls > * {
flex:1;
}

.timer__controls form {
flex:1;
display:flex;
}

.timer__controls input {
flex:1;
border:0;
padding:2rem;
}

.timer__button {
background:none;
border:0;
cursor: pointer;
color:white;
font-size: 2rem;
text-transform: uppercase;
background:rgba(0,0,0,0.1);
border-bottom:3px solid rgba(0,0,0,0.2);
border-right:1px solid rgba(0,0,0,0.2);
padding:1rem;
font-family: 'Inconsolata', monospace;
}

.timer__button:hover,
.timer__button:focus {
background:rgba(0,0,0,0.2);
outline:0;
}

.display {
flex:1;
display:flex;
flex-direction: column;
align-items: center;
justify-content: center;
}

.display__end-time {
font-size: 4rem;
color:white;
}
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ No | Guide | Demo
25 | [Event Related指南](https://github.com/soyaine/JavaScript30/blob/master/25%20-%20Event%20Related/README.md) | [Event Related效果](https://github.com/soyaine/JavaScript30/blob/master/25%20-%20Event%20Related/index-finished-Dashrun.html)
26 | [Stripe Follow Along Nav指南](https://github.com/soyaine/JavaScript30/blob/master/26%20-%20Stripe%20Follow%20Along%20Nav/README.md) | [Strip Follow Along Nav效果](https://github.com/soyaine/JavaScript30/blob/master/26%20-%20Stripe%20Follow%20Along%20Nav/index-finished-Dashrun.html)
27 | [Click and Drag指南](https://github.com/soyaine/JavaScript30/blob/master/27%20-%20Click%20and%20Drag/README.md) | [Click and Drag效果](https://github.com/soyaine/JavaScript30/blob/master/27%20-%20Click%20and%20Drag/index-finished-Dashrun.html)
28 | Video Speed Controller | -
28 | [Video Speed Controller指南](https://github.com/soyaine/JavaScript30/blob/master/28%20-%20Video%20Speed%20Controller/README.md) | [Video Speed Controller效果](https://github.com/soyaine/JavaScript30/blob/master/28%20-%20Video%20Speed%20Controller/index-finished-Dashrun.html)
29 | Countdown Timer | -
30 | Whack A Mole | -

Expand All @@ -80,7 +80,7 @@ Name | Contribution
[@DrakeXiang](https://github.com/DrakeXiang) | No.[11](https://github.com/soyaine/JavaScript30/tree/master/11%20-%20Custom%20Video%20Player)
[@zzh466](http://github.com/zzh466) | Review
[@Xing Liu](https://github.com/S1ngS1ng) | Review
[@大史快跑Dashrun](https://github.com/dashrun) | No.[16](https://github.com/soyaine/JavaScript30/tree/master/16%20-%20Mouse%20Move%20Shadow).[17](https://github.com/soyaine/JavaScript30/tree/master/17%20-%20Sort%20Without%20Articles).[18](https://github.com/soyaine/JavaScript30/tree/master/18%20-%20AddingUpTimesWithReduce).[19](https://github.com/soyaine/JavaScript30/blob/master/19%20-%20Webcam%20Fun).[20](https://github.com/soyaine/JavaScript30/tree/master/20%20-%20Speech%20Detection).[21](https://github.com/soyaine/JavaScript30/tree/master/21%20-%20Geolocation).[22](https://github.com/soyaine/JavaScript30/tree/master/22%20-%20Follow%20Along%20Link%20Highlighter).[23](https://github.com/soyaine/JavaScript30/tree/master/23%20-%20Speech%20Synthesis).[24](https://github.com/soyaine/JavaScript30/tree/master/24%20-%20Sticky%20Nav).[25](https://github.com/soyaine/JavaScript30/tree/master/25%20-%20Event%20Related).[26](https://github.com/soyaine/JavaScript30/tree/master/26%20-%20Strip%20Follow%20Along%20Nav).[27](https://github.com/soyaine/JavaScript30/tree/master/27%20-%20Click%20and%20Drag)
[@大史快跑Dashrun](https://github.com/dashrun) | No.[16](https://github.com/soyaine/JavaScript30/tree/master/16%20-%20Mouse%20Move%20Shadow).[17](https://github.com/soyaine/JavaScript30/tree/master/17%20-%20Sort%20Without%20Articles).[18](https://github.com/soyaine/JavaScript30/tree/master/18%20-%20AddingUpTimesWithReduce).[19](https://github.com/soyaine/JavaScript30/blob/master/19%20-%20Webcam%20Fun).[20](https://github.com/soyaine/JavaScript30/tree/master/20%20-%20Speech%20Detection).[21](https://github.com/soyaine/JavaScript30/tree/master/21%20-%20Geolocation).[22](https://github.com/soyaine/JavaScript30/tree/master/22%20-%20Follow%20Along%20Link%20Highlighter).[23](https://github.com/soyaine/JavaScript30/tree/master/23%20-%20Speech%20Synthesis).[24](https://github.com/soyaine/JavaScript30/tree/master/24%20-%20Sticky%20Nav).[25](https://github.com/soyaine/JavaScript30/tree/master/25%20-%20Event%20Related).[26](https://github.com/soyaine/JavaScript30/tree/master/26%20-%20Strip%20Follow%20Along%20Nav).[27](https://github.com/soyaine/JavaScript30/tree/master/27%20-%20Click%20and%20Drag).[28](https://github.com/soyaine/JavaScript30/tree/master/28%20-%20Video%20Speed%20Controller)
[@缉熙Soyaine](https://github.com/soyaine) | No.[1](https://github.com/soyaine/JavaScript30/tree/master/01%20-%20JavaScript%20Drum%20Kit).[2](https://github.com/soyaine/JavaScript30/tree/master/02%20-%20JS%20%2B%20CSS%20Clock).[3](https://github.com/soyaine/JavaScript30/tree/master/03%20-%20CSS%20%Variables).[4](https://github.com/soyaine/JavaScript30/tree/master/04%20-%20Array%20Cardio%20Day%201).[5](https://github.com/soyaine/JavaScript30/blob/master/05%20-%20Flex%20Panel%20Gallery).[6](https://github.com/soyaine/JavaScript30/blob/master/06%20-%20Type%20Ahead).[7](https://github.com/soyaine/JavaScript30/tree/master/07%20-%20Array%20Cardio%20Day%202).[8](https://github.com/soyaine/JavaScript30/tree/master/08%20-%20Fun%20with%20HTML5%20Canvas).[9](https://github.com/soyaine/JavaScript30/blob/master/09%20-%20Dev%20Tools%20Domination).[10](https://github.com/soyaine/JavaScript30/blob/master/10%20-%20Hold%20Shift%20and%20Check%20Checkboxes/README.md).[12](https://github.com/soyaine/JavaScript30/tree/master/12%20-%20Key%20Sequence%20Detection/README.md).[13](https://github.com/soyaine/JavaScript30/blob/master/13%20-%20Slide%20in%20on%20Scroll/README.md).[14](https://github.com/soyaine/JavaScript30/tree/master/14%20-%20JavaScript%20References%20VS%20Copying)

## JOIN US
Expand Down