各位同学们大家好,今天又到了周日,视频课程的时候。上次咱们讲的是日历组件。
简短的回顾一下上周的内容,免得同学们一时断篇,想不起来身在何方。日历这种东西,初学者,包括我在内,多数都会有些不知从哪里下手。会有些不太理解这东西是怎么把每个月的格,都画出来的。
其实,单纯的日历,非常简单。本质就是Date()对象的应用。
日历是几行七列的表格,那么肯定是for...for循环嵌套的了。如果哪个同学不熟悉嵌套for循环,那肯定是没写过99乘法表。
============
今天这次课就是详细的给大家讲一个日历的内部运行机制,它的不同月份的日期,到底是如何算出来的。
现在大家在自己电脑上打开“20161120_日历.html”,这个文件在QQ群的文件共享里。
做一个简单的日历,只需要三样东西:
1、通过Date()对象获取当前的年月日;
2、再获取当月1号是星期几;
3,一个包括12个月的日期的数组;
然后开始画格。无论多么复杂、有多少各种事件的日历,其实现思路都是这个顺序。
从刚才的for for例子可以看出,这个例子的外层的for循环是画每一行,内层的for循环的是每一行里的每一列,其实就是每一个格。
先来看例子当中的这句,
var idx=i*7+k;
它的作用就是给每个月的所有的格,都编上号。
下一句
var date_str=idx-firstday+1,
它的作用是,计算日期起点
怎么讲呢?i是外层的for循环的,第一次时是0;而里层的for循环k,第一次的时候也是0
那么idx在第一次的时候就是0*7+0,它的值是0;
那么date_str的值就是0-firstday + 1
这个firstday的值,在刚才我们已经通过 var firstday=n1str.getDay(); 获取当月第一天星期几,得到它的值是2,星期二嘛
那么那么date_str的值就是0-2 + 1,
这么算的,0-2 = -2,再+1,最终date_str的值是-1
至于+1这个咱们先放下
现在咱们把过滤无效日期这个先注释掉,看看会怎么样
然后是这一句
document.write ("<td align='center'>" + date_str + "</td>")
在例子中,这里是有一个三元判断的,是用来判断如果是今天,td红色背景。
其实就是把 date_str 的值 -2 写入到td中。
到这里,内for循环的第一次循环结束。
第一行的第一个格,画完了。(黑板上第一行第一个格是-1)
=====================
再来第二次,
i依然等于0,而k经过k++,已经是1了。
这时var idx=i*7+k;就变成
var idx=0*7+1;
var idx=1
var date_str=1-firstday(它获得是星期几的,值是2)+1; 计算日期起点的
var date_str=1-2+1
var date_str=-1 + 1 = 0;
到这里,内for循环的第二次循环结束。
第一行的第二个格,画完了。(黑板上第一行第二个格是0)
======================
再来第三次,
i依然等于0,而k再经过k++,已经是2了。
这时var idx=i*7+k;就变成
var idx=0*7+2;
var idx=2
var date_str=2-firstday(它获得是星期几的,值是2)+1; 计算日期起点的
var date_str=2-2+1
var date_str=0 + 1 = 1;
到这里,内for循环的第三次循环结束。
第一行的第三个格,画完了。(黑板上第一行第三个格是1)
================
依此类推直到 k<7 时,开始画第二行tr
第二行的时候,
外层的for,经过i++,i就等于1
内层的for第一次循环就变成这样:
i等于1,而k等于0
这时var idx=i*7+k;就变成
var idx=1*7+0;
var idx=7
var date_str=7-firstday(它获得是星期几的,值是2)+1; 计算日期起点的
var date_str=7-2+1
var date_str=5 + 1 = 6;
到这里,内for循环的第二次循环结束。
第二行的第一个格,画完了。(黑板上第二行第1个格是6)
================
再来第二次
再来第二次,
i依然等于1,而k经过k++,已经是1了。
这时var idx=i*7+k;就变成
var idx=1*7+1;
var idx=8
var date_str=8-firstday(它获得是星期几的,值是2)+1; 计算日期起点的
var date_str= 8-2+1
var date_str= 6 + 1 = 7;
到这里,内for循环的第二次循环结束。
第二行的第二个格,画完了。(黑板上第二行第二个格是7)
==============
依此类推,
直到 i < tr_str 时,整个for循环结束
tr_str是日历的行数
============
现在大家看到的是这个样子的日历,
日历的开头有-1,0,结尾处画出了33号。
这说明需要过滤一下无效日期,现在把例子中那句过滤无效日期的JS代码,给取消注释,再刷新页面,日历就正常了。
这段话的意思很简单,date_str的值就是每一个格里的日期数字。当它小于或等于0 || 或是大于每个月份的日期,满足这二个条件时,date_str的值就是空格,否则就是真正的值。
那开头的-1和0,肯定是小于等于0了,于是前二个格就是空白;结尾的数字肯定大于当月的月份数字了,所以也是空格。
这就是整个日历的完成思路。
至于获得每个月的月份日期,是通过获取数组m_days[mnow]里的第mnow个月份来得到手。
大家看例子上半部分,数组m_days里存着12个月份,每个月的总天数。
这个视频必须对照着例子一边看,一边调试才能看得明白。
========================
这个例子的核心,就是用嵌套for循环,来实现Date()对象的操作。
它的特征是列数固定,一周七天,所以下一行的数字,总是外层for循环中i的值乘7,再加上内层for循环K的值。这样每下一行的数字都是在前一或几行的数字基础再加。而不会重头计起。
为什么日历讲这么多呢,你看这里都没有讲什么React。因为它在我个人主观看来,是真正的在操作对象和数据。对象就是Date()日期对象,数据嘛,如果我们传入一些东西,就有数据了。
大家回去这个一定要多练,否则理解不透。直接点讲,我讲明白了,但你不练导致理解不了,那你这钱就白花了。
============
再跟大家讲一下,在实际的工作中,我们需要手动的去写日历的工作场景,实际上并不多见。那为什么还要让大家来学习日历呢?
盖因为呀,日历确实就是非常非常的常用的一个组件。很多时候我们都需要根据自己的业务需求,去订制化的搞一款日历组件。
但日历组件这个东西,在实际工作中其实是挺复杂却又单一的东西。单一是说它不管怎么着,也就是个日历。
复杂是说,首先要显示日期;然后是可以选择起始日和结束日,然后特定日期的事件提醒、日程安排,然后又可以上下月切换、年切换、日切换。还要有可移植性,跨平台、跨终端等要求。等到日历写成这样的时候,就已经相当复杂了。
在这种情况下,如果我们还是自己去手动的写一款日历组件,就会耗用较多的工时。而这是不必要的工时开销,还容易出错。
所以很多时候,我们都是会去找一款日历插件,根据自己的业务需求,来对它进行相应的修改。一般在这种时候,就需要你能够看懂日历插件的源码,看不懂源码,你怎么修改呢?
不懂原理,就没法改日历插件;不修改插件,基本上没法直接拿来用。很多时候还要修改日历组件的API调用接口,使之符合本公司的项目要求。
更多的时候,是公司有一个积累而成的前端组件库,或是直接花钱买一个前端UI库,里面就包含日历插件了。
这么说吧,日历就基本没有自己写的,都是在网上找现成的修改。但你必须要看懂它的源码,得知道日历的运行原理才行,而这就是我们学习日历组件的目的。
============
大家平时做练习的时候,一定要理解业务,在切图的时候要想想它实际是怎么运行的?
一定要看看大公司,大网站的页面是怎么做的,名字是怎么起的。因为它们就是事实上的标准,否则自己就在那瞎切,纯纯的无用功。