fullCalendar改造计划之带农历节气节假日的万年历
计划着要做一款万年历,作为自己小项目的便民功能。
作为一枚“资深”业余前端,本想着网上应该有现成的代码可用,一顿猛搜之后,倒是确实搜到几个,但是一看功能,跟我想的不一样;再看代码,顿时没有了修改的欲望。顿时大失所望,理想太丰满,现实太骨感啊!!
无意搜到一款jquery的日程安排日历插件,fullCalendar(官网:http://arshaw.com/fullcalendar/),
发现嗯,功能貌似挺强大的嘛,再一看,最近更新日期是2013年9月,于是决定了,改造!
下载下来的最新版是fullcalendar-1.6.4,原生的样子是这样的:
但是我想象的应该是这个样子的:
貌似差别有点大……没关系,一步步来改造。
一、当然是汉化啦
需要汉化的地方不多,就一些英文的月份,周几而已,简单修改一下
// locale
isRTL: false,
firstDay: 0,
monthNames: ['一月','二月','三月','四月','五月','六月','七月','八月','九月','十月','十一月','十二月'],
monthNamesShort: ['一月','二月','三月','四月','五月','六月','七月','八月','九月','十月','十一月','十二月'],
dayNames: ['星期日','星期一','星期二','星期三','星期四','星期五','星期六'],
dayNamesShort: ['周日','周一','周二','周三','周四','周五','周六'],
buttonText: {
prev: "<span class='fc-text-arrow'>‹</span>",
next: "<span class='fc-text-arrow'>›</span>",
prevYear: "<span class='fc-text-arrow'>«</span>",
nextYear: "<span class='fc-text-arrow'>»</span>",
today: '返回今天',
month: '月',
week: '周',
day: '日'
},
按钮显示的内容,除了可以直接改源文件之外,也可以在页面的初始化js中配置“buttonText”的值,比如:
buttonText: {
prev: "<span class='fc-text-arrow'>‹上个月</span>",
next: "<span class='fc-text-arrow'>下个月›</span>",
prevYear: "<span class='fc-text-arrow'>«上一年</span>",
nextYear: "<span class='fc-text-arrow'>下一年»</span>"
},
简单汉化后就成了这样:
二、添加农历,节气,节假日的信息显示
作为一款万年历,没有这些中国特色的东西,出门都不好意思说自己是日历。
要显示这些农历,节假日信息,有两种方法:
一是直接调用google calendar的订阅地址,把这些信息通过配置fullCalendar自带的events的方式,像显示日程安排一样显示出来,fullCalendar是原生支持google calendar调用的(不过貌似只能调一个文件);
比如官方示例里的显示美国节假日的例子:
// US Holidays
events: 'http://www.google.com/calendar/feeds/usa__en%40holiday.calendar.google.com/public/basic'
换一下源地址中的ID部分,就可以显示其他日程,比如:
中国节假日(Calendar ID: china__zh_cn@holiday.calendar.google.com); 农历(Calendar ID: lunar__zh_cn@holiday.calendar.google.com);
二是直接修改源文件,这个相对第一种直接调相对麻烦些,不过好处就是可以完全自定义,想怎样就怎样……毫无疑问,作为一个患有轻微代码强迫症的程序猿,果断选择自己修改源文件,至于events方式,就留着以后用来显示假期安排吧。
既然要自定义,那就需要一个节气节假日以及农历信息的库,比较了一下各大导航站(因为导航站一般都有万年历……),在hao123扒到一个看起来不错的js库(点我查看lunar.js),包含了农历,节气和节假日。嗯……hao123的日历风格貌似也挺不错,OK,就它了!
为了方便,直接把lunar.js的内容拷到fullCalendar的js文件fullCalendar.js里;然后就可以修改显示日期的单元格的内容和样式啦。直接贴修改的代码:
if (showNumbers) {
html += "<div class='fc-day-number'>" + date.getDate() + "</div>";
// modified by feifei.im 增加节气显示
var cTerm = lunar(date).term;
if(cTerm){
html += "<div class='fc-day-cnTerm'>"+cTerm+"</div>";
}
// modified by feifei.im 增加节日显示
var fes = lunar(date).festival();
if(fes && fes.length>0){
html += "<div class='fc-day-cnTerm'>"+$.trim(fes[0].desc)+"</div>";
}
// modified by feifei.im 无节日节气时,增加农历显示
if(!cTerm && (!fes || fes.length==0)){
html += "<div class='fc-day-cnDate'>"+lunar(date).lMonth + "月" + lunar(date).lDate +"</div>";
}
}
这边为了保持整齐,如果当前日期有节气或者节假日的话,就不显示农历了
OK,现在节气节假日已经可以显示了
三、添加年月下拉框,方便选择日期
现在的日历大体功能已经实现了,但是有一点比较影响用户体验:现在要是想看几年前或者几个月前的日期,必须一次次的点“上一年”,“上个月”的按钮,直到点到需要的日期。一两年也就罢了,十几二十年的话就纠结了……
所以,添加一个下拉框用来显示并选择当前年月信息还是很有必要滴……
方便起见,直接把fullCalendar的“title”部分修改成下拉框(也就是下图显示的这个部分):
直接贴代码:
1.修改title的内容,原生的是直接显示文字,改成下拉框的形式
$.each(this.split(','), function(j, buttonName) {
if (buttonName == 'title') {
//e.append("<span class='fc-header-title'><h2> </h2></span>");
// modified feifei.im 下拉框选择年月
var selectHtml = '';
var i = 0;
selectHtml +="<span id='fc-dateSelect' class='fc-header-title'>";
selectHtml +="<select name='fcs_date_year' id='fcs_date_year' class='selectable m_year mr15'>";
// 循环年份
for(i=1901;i<=2100;i++){
selectHtml +="<option value='"+i+"'>"+$.trim(i+"年")+"</option>";
}
selectHtml +="</select>";
selectHtml +="<select name='fcs_date_month' id='fcs_date_month' class='selectable m_year'>";
// 循环月份
var monthDigitCN = ['一', '二', '三', '四', '五', '六', '七', '八', '九', '十', '十一', '十二'];
for(i=0;i<=11;i++){
selectHtml +="<option value='"+i+"'>" +$.trim(monthDigitCN[i]+"月") + "</option>";
}
selectHtml +="</select>";
selectHtml +="</span>";
e.append(selectHtml);
if (prevButton) {
prevButton.addClass(tm + '-corner-right');
}
prevButton = null;
}
2.修改原title更新方法,之前是修改title的文本,改成修改下拉框的选中值
function updateTitle(html) {
//element.find('h2').html(html);
// modified feifei.im 更新title时修改为下拉框
var shtm = html.split(" ");
if(shtm && shtm.length>1){
$("#fcs_date_month").find("option").filter(function(){return ($(this).text() == $.trim(shtm[0]));}).prop('selected', true);
$('#fcs_date_year option[value="'+$.trim(shtm[1])+'"]').prop('selected', true);
}
}
这边有个坑,网上流传的根据select的text值修改select的选中状态的代码根本没用啊!! 就是这货$('#fcs_date_month option[text="'+$.trim(shtm[1])+'"]').attr('selected', true); 后来改成上面的“$("#fcs_date_month").find("option").filter……”这种实现方式才可以
3.此时下拉框已经能随着当前月份年份的变化自动改变选中的值,但是用户自己选择年份月份的时候还是没有任何反应的……所以得给下拉框绑定相应的响应事件
由于下拉框是动态生成的,所以用delegate来绑定,并调用fullCalendar插件自带的跳转到某个日期的方法“gotoDate”。
代码如下
/** 绑定事件到日期下拉框 **/
$(function(){
$("#fc-dateSelect").delegate("select","change",function(){
var fcsYear = $("#fcs_date_year").val();
var fcsMonth = $("#fcs_date_month").val();
$("#calendar").fullCalendar('gotoDate', fcsYear, fcsMonth);
});
});
4.OK,下拉框显示并选择日期功能改造成功
四、添加日期详细信息显示
经过简单改造,fullCalendar已经可以满足要求了,不过为了更好的用户体验嘛,可以加上一个显示当天日期的详细信息(天干地支,生肖节气什么的)的功能(好吧,我会告诉你我是赤果果的在抄hao123么……)
老规矩,直接贴代码:
官方示例里,只有一个
<div id="calendar"></div>
用来显示日历控件的相关内容,现在我们把它扩展下,加点东西
<!-- 加载提示 -->
<div id="msgTopTipWrapper">
<div id="msgTopTip">
<span><i class="iconTip"></i>正在载入日历数据...</span>
</div>
</div>
<div class="calendarWrapper">
<!-- 日期详细信息 -->
<div class="rightSidePanel mb50 fr">
<div id="div_day_detail" class="h_calendar_alm">
<div class="alm_date"></div>
<div class="alm_content nofestival">
<div class="today_icon"></div>
<div class="today_date"></div>
<p id="alm_cnD"></p>
<p id="alm_cnY"></p>
<p id="alm_cnA"></p>
<div class="alm_lunar_date"></div>
</div>
</div>
</div>
<!-- 日历主体 -->
<div id="calendar" class="dib"></div>
</div>
然后加上页面加载时初始化今日详细信息的js代码:
/** 当天信息初始化 **/
$(function(){
var dayDate = new Date();
var d = $.fullCalendar.formatDate(dayDate,"dddd");
var m = $.fullCalendar.formatDate(dayDate,"yyyy年MM月dd日");
var lunarDate = lunar(dayDate);
$(".alm_date").html(m + " " + d);
$(".today_date").html(dayDate.getDate())
$("#alm_cnD").html("农历"+ lunarDate.lMonth + "月" + lunarDate.lDate);
$("#alm_cnY").html(lunarDate.gzYear+"年 "+lunarDate.gzMonth+"月 "+lunarDate.gzDate+"日");
$("#alm_cnA").html("【"+lunarDate.animal+"年】");
var fes = lunarDate.festival();
if(fes.length>0){
$(".alm_lunar_date").html($.trim(lunarDate.festival()[0].desc));
$(".alm_lunar_date").show();
}else{
$(".alm_lunar_date").hide();
}
});
加上对应的css样式后,现在刷新页面已经可以看到当天的详细信息了,但是我们需要可以查看每天的详细信息,所以要给日期的单元格加上对应的触发时间,fullCalendar已经有这功能了,配置一下就OK,同时顺便配置一下加载提示信息的显示与隐藏:
dayClick : function(dayDate, allDay, jsEvent, view) { //点击单元格事件
var d = $.fullCalendar.formatDate(dayDate,"dddd");
var m = $.fullCalendar.formatDate(dayDate,"yyyy年MM月dd日");
var lunarDate = lunar(dayDate);
$(".alm_date").html(m + " " + d);
$(".today_date").html(dayDate.getDate())
$("#alm_cnD").html("农历"+ lunarDate.lMonth + "月" + lunarDate.lDate);
$("#alm_cnY").html(lunarDate.gzYear+"年 "+lunarDate.gzMonth+"月 "+lunarDate.gzDate+"日");
$("#alm_cnA").html("【"+lunarDate.animal+"年】");
var fes = lunarDate.festival();
if(fes.length>0){
$(".alm_lunar_date").html($.trim(lunarDate.festival()[0].desc));
$(".alm_lunar_date").show();
}else{
$(".alm_lunar_date").hide();
}
// 当天则显示“当天”标识
var now = new Date();
if (now.getDate() == dayDate.getDate() && now.getMonth() == dayDate.getMonth() && now.getFullYear() == dayDate.getFullYear()){
$(".today_icon").show();
}else{
$(".today_icon").hide();
}
},
loading : function(bool) {
if (bool)
$("#msgTopTipWrapper").show();
else
$("#msgTopTipWrapper").fadeOut();
}
至此,改造之后的fullCalendar已经满足要求啦。至此基本改造完成,下一步的目标是要在日历上显示节假日的放假上班安排,这个可以通过fullCalendar的events配置,后端生成相应json来实现。
配置很简单,就是之前配置events的方法,只不过地址换成自己的:
events : "${ctx}/topic/rili/getFestival",
然后后端对应的返回相应的json串即可,比如我用的springMVC就这么搞:
@ResponseBody
@RequestMapping(value="/topic/rili/getFestival",method = RequestMethod.GET)
public List<Map<String,Object>> riLiGetFestival() {
List<Map<String,Object>> festivalList = new ArrayList<Map<String,Object>>();
// 2014全部假期日期表
String holidayTitles = "春节假期;清明节假期;劳动节假期;端午节假期;中秋节假期;国庆节假期;元旦假期;春节调休上班;春节调休上班;劳动节调休上班;国庆节调休上班";
String holidayStarts = "2014-1-31;2014-4-5;2014-5-1;2014-5-31;2014-9-6;2014-10-1;2014-1-1;2014-1-26;2014-2-8;2014-5-4;2014-9-28;2014-10-11";
String holidayEnds = "2014-2-6;2014-4-7;2014-5-3;2014-6-2;2014-9-8;2014-10-7;2014-1-1;2014-1-26;2014-2-8;2014-5-4;2014-9-28;2014-10-11";
String[] arrHolidayTitles = holidayTitles.split(";");
String[] arrHolidayStarts = holidayStarts.split(";");
String[] arrHolidayEnds = holidayEnds.split(";");
for (int i=arrHolidayTitles.length-1;i>=0;i--){
Map<String,Object> map = new HashMap<String,Object>();
map.put("id", i);
map.put("title", arrHolidayTitles[i]);
map.put("start", arrHolidayStarts[i]);
map.put("end", arrHolidayEnds[i]);
festivalList.add(map);
}
return festivalList;
}
这样就能显示假期信息啦
修改后的相应的源码以及css样式文件需要的童鞋可以戳下面的链接下载下来看看哦~
非常感谢你做的修改,最近我项目实训刚好用到这个日历!
——————————————————
顺便说一句,你的评论系统可以用多说。
哈,博客评论也不多,就懒得再加个多说插件啦
最近正在学习这个,你的修改给了我不少的帮助!
谢谢你的分享, 如果想在假期的格子变成红色, 如何更改!!
好久没看这个了,大概重新看了下。
由于event方式显示节假日,会自动生成新的div层浮动显示在日期上面,对日期显示的格子是不做操作的。
所以我觉得如果要让格子变色的话,可以不用event这种方式,直接把假期日期写在js里面,然后通过每个日期格子的“data-date”属性来找到对应的假期格子,然后再修改样式
对不起! 小弟只是刚学习中, 可否教导一下, 谢谢!!
我也是自己无聊摸索的着玩的~~指导谈不上,一起看看吧~
这个方法是构造输出日期单元格的,在这个方法里,你可以加一段代码来根据日期控制输出单元格的样式,比如我看了下源码的实现,我觉得有一种简单的修改方式,你可以参考参考。
在fullcalendar.js文件的
其中holidaysArr里面把当年的假期信息都列出来,当然这边也可以搞个外部json,从json里读。
这样,每个你列出来的假期的td单元格都被加上了“holidayBgColor”这个样式,然后自己在CSS文件里定义下这个样式就OK了
已照你的方法去做,但是不成功。
在CSS文件里定义了
.holidayBgColor {
background-color: red;
};
我这边本地试过是可以的,不知道你那边为什么不可以,我给你发邮件了
谢谢你的分享
请问一下,我想用GOOGLE假期应该要怎么改呢
还有我想升级fullcalendar的版本应该没问题吧
谢谢
GOOGLE假期的话应该官方有示例吧,用events的方式配一配应该就行了
因为我是修改了源码实现的农历,升级fullcalendar版本的话要照着之前修改的步骤再重新修改一遍才行~文件结构估摸着应该没太大变化吧……好久没关注了
升級好難,
請問feifei
假期的數字可以改顏色嗎
謝謝了
这种改源码的升级确实有点纠结~~
数字颜色可以改的,参照上面的评论,那个是改假期格子颜色的,改数字颜色的话把CSS定义下应该就可以了
升级了fullcalendar,但是GCAL还是用不了
继续用1.6.4好了
holidaysArr可以用VAR FESTIVAL的数据吗
这样就不用再定义多一次了
非常感谢你的帮忙
又試了升级fullcalendar,GCAL可以用了
请问feifei
Fullcalendarv2.2.3要怎么样才可以同时用gcal和php array event啊
谢谢
你是想既使用农历又使用google Calendar?
把events注掉,试试看eventSources呢
本想试试,但是发现Google不支持V2的Calendar了。。。V3的话貌似还得升级fullCaladar,所以就不试了~
我用了都不行, 谢谢
feed.php output
评论被识别为spam放在垃圾箱了……今天清理才发现
过了这么长时间不知道你解决没……
那个解决方案我也是google出来的,这个不行的话俺暂时也不知道拉,没太详细的研究过这个^_^
不过看feed.php返回的json串挺奇怪的样子~~
赞赞赞赞赞赞赞赞赞!! 这样式好好看!
你好 请问下 这个月份 比如 十二月初一 九月初一, 怎么能把 前面的月份去掉 就留下具体多少号,
上面修改的地方有代码的
把这里面的月份去掉就行了
你好,我看到代码里面有
this.gzChrono = DB.earthlyBranches[Math.floor((this.oDate.getHours() + 1) / 2)] '子';
请问,能把添加时间的天干贴出来吗?现在只有地支。
谢谢你 之前的问题解决了 ,你好 请问怎么能 控制日期呢? 因为我要做的事情是 类似于某天以后事需要办理 日历给个提醒,希望在日期框里的左上角做个标示。
或者是我把日期标红,后台返回日期 比如是2015-02-05 我希望能再日历上控制这天 然后标红 谢谢
我用了这套方法 但是IE不支持 因为childNodes支持的特别不好 兼容性太差 火狐是好使的
(function(){
提醒功能其实就是标识节假日的那个功能,只不过开始日期和结束日期都是同一天而已,提醒的标题也可以自定义
单独控制某一天的话,其实每个日期的单元格都有个
data-date
的属性的,这个属性就是表示了当前单元格的日期;我觉得可以根据这个来对你需要修改的日期单元格进行dom操作,改变样式什么的
现在的代码,比如点击今天(2015-2-5)的单元格,右边的今日详细会显示“乙未年 戊寅月 壬子日”,这里面已经包含了天干地支呀。
如果说是要在单元格里显示的话,可以参考今日详细的显示每个单元格都计算一遍然后显示出来
看不太懂这段代码的意思,如果是要取某个日期单元格进行dom操作的话,可以循环校验
data-date
,比如:谢谢 原来是这样 哎 新人 谢谢你 博主 看了你的帖子 真是受益匪浅 谢谢
晚安 祝你好梦 等明天我试试 刚看见邮件 谢谢
lunar.js能发我一份吗?网上下的没有lunar定义
hao123都能找到 或者在博主的JS里 就有
文章里有个
点我查看lunar.js
……点一下就有了……地址是
http://feifei.im/usr/uploads/2013/10/lunar_demo.js
^_^
feifei博主,当我点击下一个月 或者上一个月的时候 我的标红就会被刷新没了。这个需要修改源码吧。无从下手了。我看原来了_renderView 完全傻眼了,
有乱码啊,不过我从文章最后找到下载了,还有不知道能不能把国定假日注明出来