diff --git a/29 - Countdown Timer/README.md b/29 - Countdown Timer/README.md new file mode 100644 index 0000000..901dc8e --- /dev/null +++ b/29 - Countdown Timer/README.md @@ -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); +} +``` + +## 延伸思考 +本次代码中前后会定义定时器和清除定时器,另一种做法是定时器一直工作不清除,对应的按钮和表单只修改时间,不用调整定时器,当值发生变化后,下一秒定时器检测时就会开始倒计时,这样代码逻辑上会有所简化,感兴趣的朋友可以自行练习。 \ No newline at end of file diff --git a/29 - Countdown Timer/effect.png b/29 - Countdown Timer/effect.png new file mode 100644 index 0000000..6334ccb Binary files /dev/null and b/29 - Countdown Timer/effect.png differ diff --git a/29 - Countdown Timer/index-start.html b/29 - Countdown Timer/index-start.html new file mode 100644 index 0000000..d54f447 --- /dev/null +++ b/29 - Countdown Timer/index-start.html @@ -0,0 +1,29 @@ + + + + + Countdown Timer + + + + +
+
+ + + + + +
+ +
+
+
+

+

+
+
+ + + + diff --git a/29 - Countdown Timer/scripts-START.js b/29 - Countdown Timer/scripts-START.js new file mode 100644 index 0000000..2d3747c --- /dev/null +++ b/29 - Countdown Timer/scripts-START.js @@ -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); +} + diff --git a/29 - Countdown Timer/style.css b/29 - Countdown Timer/style.css new file mode 100644 index 0000000..f240799 --- /dev/null +++ b/29 - Countdown Timer/style.css @@ -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; +} diff --git a/README.md b/README.md index 3b1775f..872ae50 100644 --- a/README.md +++ b/README.md @@ -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 | - @@ -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