原生JS学习之秒表、日历
Tips:涉及知识点:Date setInterval DOM
秒表
效果图:

简单构造出草图

Html代码
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <title>时间Demo</title> 5 <meta charset="utf-8"> 6 <link rel="stylesheet" type="text/css" href="css/time.css"> 7 </head> 8 <body> 9 <div align="center"> 10 <!-- 导航栏 --> 11 <div id = "nav"> 12 <a href="#">闹钟</a> 13 <a href="#">计时器</a> 14 <a href="#" style="color:white">秒表</a> 15 </div> 16 17 <!-- 时钟 --> 18 <div id = "timer" align="center"> 19 <br> 20 <span id = "title">Timer</span><br> 21 <span id = "tips" class = "timer"> M S </span><br> 22 <span id = "tim" class = "timer">00:00</span><br> 23 <span id = "s" class = "timer">00</span> 24 </div> 25 <!-- 底部按钮 --> 26 <div id = "footer"> 27 <table> 28 <tr> 29 <td><button onclick = "start()" id = "start">开 始</button></td> 30 <td><button onclick = "stop()">暂 停</button></td> 31 <td><button onclick = "re()">复 位</button></td> 32 </tr> 33 </table> 34 </div> 35 </div> 36 <script type="text/javascript" src = "js/time.js"></script> 37 </body> 38 </html>
中间使用了大量的 <br> 是因为我目前不太会调这个细节,只好拿这些来补位
CSS代码
1 body{
2 background: black;
3 }
4 a{
5 color:gray;
6 text-decoration:none;
7 font-size:larger;
8 }
9 #nav{
10 border-bottom:1px solid orange;
11 width: 50%;
12 text-align: left;
13 padding-bottom: 10px;
14 }
15 #timer{
16 margin-top: 20px;
17 margin-bottom: 20px;
18 height: 250px;
19 width: 250px;
20 border-radius:50%;
21 border:5px dashed skyblue;
22 text-align: center;
23
24 }
25 #title{
26 color:gray;
27 font-size:xxx-large;
28 }
29 #tim{
30 font-size:xxx-large;
31 }
32 #tips{
33 font-size: x-large;
34 }
35 .timer{
36 color:white;
37 }
38 #s{
39 font-size:xx-large;
40 }
41 button{
42 background: orange;
43 color:gray;
44 width: 80px;
45 height: 30px;
46 border: none;
47 outline: none;
48 font-size:large;
49 }
50 button:hover{
51 color:black;
52 }
53 table{
54 width: 600px;
55 border-collapse: collapse;
56 border-spacing: 0;
57 table-layout: fixed;
58 text-align:center;
59
除了常见的样式,还加了一些现查的
比如
实现a标签去除原有样式: text-decoration:none;
按钮的边框去除
border: none;
outline: none;
JS实现
思路分析:
我第一下想象到的是Js的计时器,setInterval(),然后每10ms执行一次,然后是纯逻辑判断,不用任何内置对象。后来发现,如果是这样,那么会很复杂,判断条件也很多。
后来想到了Date对象,可以通过点击时与当前时间做差值运算,这样就少了很多边界条件的判断。
首先是取得节点,clc是用来获得计时器的标志位,方便后来停止
1 var time = document.getElementById("tim");
2 var ss = document.getElementById("s");
3 var clc = null;
开始按钮点击时进行的操作:
1 function start(){
2 clearInterval(clc);//防止点击两次之后,无法停止计时器的问题
3 let time2=new Date().getTime();
4 clc = setInterval(function(){
5 let times = new Date().getTime() - time2;
6 let minutes=Math.floor(times/60000);
7 let seconds=Math.floor((times-minutes*60000)/1000);
8 let ms=Math.floor((times-minutes*60000-seconds*1000)/10);
9 time.innerText = (minutes<10 ? "0" +minutes : minutes)+":"
10 +(seconds<10 ? "0"+seconds :seconds);
11 ss.innerText = ms<10?"0"+ms:ms;
12 }, 10);
13 }
new Date().getTime() 使用来获取当前时间到1970年1月1日的毫秒数
通过取余,取整,补零等简单的操作,就可以得到时间,然后每10毫秒渲染在页面上一次。
暂停和复位JS
1 function stop(){
2 clearInterval(clc);
3 }
4
5 function re(){
6 time.innerText = "00:00";
7 ss.innerText = "00";
8 }
到这里,功能基本实现,但是留下了一个疑问
秒表计时是按照点击开始的时间和每过10ms的时间计算得到的,那么再此点击开始,时间就会从0开。
但所给的最终效果只是一个图片,无法判断接下来要实现的功能。
如果扩展的话,可以加上一个参数,就是按下暂停的时间(页面上显示的)。
日历
效果图

这个结构也很明显,所以直接上手
Html代码
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta charset="utf-8"> 5 <title>日历Demo</title> 6 <link rel="stylesheet" type="text/css" href="css/date.css"> 7 </head> 8 <body> 9 <div id = "main" align="center"> 10 <!-- 标题 --> 11 <div id = "title"> 12 <h2>模拟日历</h2> 13 </div> 14 15 <!-- 输入框 --> 16 <div > 17 <span>年</span> 18 <input type="text" id = "year"> 19 <span>月</span> 20 <input type="text" id = "month"> 21 <span> </span> 22 <input type="button" id = "btn" value="生 成" onclick = "fun()"> 23 </div> 24 25 <!-- 日历 --> 26 <div id = "calendar"> 27 28 <div id = "date"> 29 <span id = date2></span> 30 </div> 31 <div> 32 <table border = 0 id = "week" > 33 <tr> 34 <td>Sun</td> 35 <td>Mon</td> 36 <td>Tue</td> 37 <td>Wed</td> 38 <td>Thu</td> 39 <td>Fri</td> 40 <td>Sat</td> 41 </tr> 42 </table> 43 </div> 44 <div id = "month2"> 45 <table id = "day" border ="1" cellpadding="0" cellspacing="0"> 46 <tr> 47 <td></td> 48 <td></td> 49 <td></td> 50 <td></td> 51 <td></td> 52 <td></td> 53 <td></td> 54 </tr> 55 <tr> 56 <td></td> 57 <td></td> 58 <td></td> 59 <td></td> 60 <td></td> 61 <td></td> 62 <td></td> 63 </tr> 64 <tr> 65 <td></td> 66 <td></td> 67 <td></td> 68 <td></td> 69 <td></td> 70 <td></td> 71 <td></td> 72 </tr> 73 <tr> 74 <td></td> 75 <td></td> 76 <td></td> 77 <td></td> 78 <td></td> 79 <td></td> 80 <td></td> 81 </tr> 82 <tr> 83 <td></td> 84 <td></td> 85 <td></td> 86 <td></td> 87 <td></td> 88 <td></td> 89 <td></td> 90 </tr> 91 <tr> 92 <td></td> 93 <td></td> 94 <td></td> 95 <td></td> 96 <td></td> 97 <td></td> 98 <td></td> 99 </tr> 100 </table> 101 </div> 102 </div> 103 </div> 104 105 <script type="text/javascript" src = "js/date.js"></script> 106 </body> 107 </html>
CSS代码
1 body{
2 background: url(../img/img1.jpg);
3 Background-size:100%;
4 }
5 #main{
6 margin:30px auto;
7 height: 600px;
8 width: 700px;
9 background: rgba(255,255,255,0.5);
10 }
11 #title{
12 text-align: left;
13 padding-top: 5px;
14 padding-left: 20px;
15 }
16 #btn{
17 background: #036;
18 color: white;
19 border: none;
20 outline: none;
21 height: 30px;
22 width: 70px;
23 }
24 input{
25 height: 25px;
26 width: 180px;
27 }
28 #calendar{
29 width: 350px;
30 height:auto;
31 margin-top: 10px;
32 }
33 #date{
34 font-size:x-large;
35 height: 50px;
36 width: 100%;
37 background: #036;
38 border-radius: 5px;
39 margin: 0 auto;
40 color: white;
41 }
42
43 #week{
44 height: 50px;
45 width: 100%;
46 background: #ccc;
47 text-align: center;
48 font-weight:600;
49 }
50 #week tr td{
51 width: 50px;
52 }
53 #day{
54 width:100%;
55 background: #ccc;
56 text-align: center;
57 }
58 #day tr td{
59 height: 50px;
60 width: 50px;
61 }
62 .t{
63 background: white;
64 }
这些都做完,一个大概的轮廓就出来了

那么接下来,就是获取输入的年月,并渲染了
JS实现
思路分析
年月的获得,就是节点取值的问题,为了方便后续进行,我加了简单的正则判断
var year_reg = /^\d{1,4}$/;
var month_reg = /^1[0-2]$|[1-9]/;
然后我需要几个很关键的数据
首先是上个月的天数,因为在大多数情况下,第一行我需要用灰色显示上个月的几天。
同时考虑到如果是一月,那么上一月的年份也会换,所以也加了判断条件。
var lastDate = parseInt(month==1?31:new Date(year,month-1,0).getDate());
其次是当前月的天数,因为后面要获取到下个月开始的日期
var thisDate = parseInt(new Date(year,month,0).getDate());
然后是当前月第一天的星期
var thisDate_one = parseInt(new Date(year,month-1,1).getDay());
由于最后一个参数不是0,所以月份要-1(取值范围的问题)
然后是复杂的循环的拼(字符)串,这也是日历的核心
1 var str = "<table id = 'day' border ='1' cellpadding='0' cellspacing='0'>";
2 for(let i = 1;i<=6;i++){
3 str+="<tr>";
4 for(let j = 1;j<=7;j++){
5 if(i==1){
6 str+=j<thisDate_one+1?"<td>"+(lastDate-thisDate_one+j)+"</td>":"<td class='t'>"+(j-thisDate_one)+"</td>";
7 }else if(i>=5){
8 str+=(j-thisDate_one+(i-1)*7)>thisDate?"<td>"+(j-thisDate_one+(i-1)*7)%thisDate+"</td>":"<td class='t'>"+(j-thisDate_one+(i-1)*7)+"</td>";
9 }else{
10 str+="<td class='t'>"+(j-thisDate_one+(i-1)*7)+"</td>";
11 }
12 }
13 str+="</tr>";
14 }
15 str+="</table>";
16 day.innerHTML = str;
17 return;
最重要的就是第四行的for循环里面。
会有三种情况,就是首行,中间,尾行(1行或两行)
首行,判断i==1
然后再与第一天的星期相比,小于则执行上个月的循环。
拿2020年8月举例
第一天是周六,那么第一天之前,他的<td>里的数据就是上个月的天数 - 这个月的天数 + j(行号)
即
lastDate-thisDate_one+j
代码上加上了括号是因为NaN的问题
然后当前月的循环就是 行号-当前月的第一天
j - thisDate_one
第二个判断条件是尾行,我们知道从第五行开始,可能就进入了下个月,那么又要重新考虑逻辑
判断是否进入了下个月,需要判断是否大于当前月的天数,这里也使用了一个三目运算
str+=(j-thisDate_one+(i-1)*7)>thisDate?"<td>"+(j-thisDate_one+(i-1)*7)%thisDate+"</td>":"<td class='t'>"+(j-thisDate_one+(i-1)*7)+"</td>";
因为周数的迭代,所以要加上( i - 1 )* 7 同时巧妙的利用取余运算来得出<td>的内容
后面因为小于,按正常计算就可以
中间比较简单
str+="<td class='t'>"+(j-thisDate_one+(i-1)*7)+"</td>";
接下来是完整的JS代码
1 var year_reg = /^\d{1,4}$/;
2 var month_reg = /^1[0-2]$|[1-9]/;
3
4 function fun(){
5 var year = document.getElementById("year").value;
6 var month = document.getElementById("month").value;
7 if (year_reg.test(year)&&month_reg.test(month)) {
8 document.getElementById("date2").innerText = year+"年"+month+"月";
9 var thisDate = parseInt(new Date(year,month,0).getDate());
10 var lastDate = parseInt(month==1?31:new Date(year,month-1,0).getDate());
11 var day = document.getElementById("month2");
12 var thisDate_one = parseInt(new Date(year,month-1,1).getDay());
13 var str = "<table id = 'day' border ='1' cellpadding='0' cellspacing='0'>";
14 for(let i = 1;i<=6;i++){
15 str+="<tr>";
16 for(let j = 1;j<=7;j++){
17 if(i==1){
18 str+=j<thisDate_one+1?"<td>"+(lastDate-thisDate_one+j)+"</td>":"<td class='t'>"+(j-thisDate_one)+"</td>";
19 }else if(i>=5){
20 str+=(j-thisDate_one+(i-1)*7)>thisDate?"<td>"+(j-thisDate_one+(i-1)*7)%thisDate+"</td>":"<td class='t'>"+(j-thisDate_one+(i-1)*7)+"</td>";
21 }else{
22 str+="<td class='t'>"+(j-thisDate_one+(i-1)*7)+"</td>";
23 }
24 }
25 str+="</tr>";
26 }
27 str+="</table>";
28 day.innerHTML = str;
29 return;
30 }
31 alert("输入不合法");
32 return;
33 }
感谢您的阅读

浙公网安备 33010602011771号