avalon.js实现一个简易日历
使用MVVM框架avalon.js实现一个简易日历
最近在做公司内部的运营管理系统,因为与日历密切相关,同时无需触发条件直接显示在页面上,所以针对这样的功能场景,我就用avalon快速实现了一个简易日历,毕竟也是第一次造日历这种轮子,所以这里记录下我当时的一些思路,一来做一些技术总结,二来也是给像我这样第一次做日历的前端工程师一些参考。
先来一起看下日历的界面:

日历功能包括:1.显示当前月、上个月后几天、下个月前几天的日期,2.切换到上个月,3.切换到下一个月,4.回到今天,5.点击某天弹出当天的年月日(如2014-10-26),同时不在当前月的日期以更淡的颜色与当前月进行一个区分。
因为使用avalon进行实现,了解MVVM思想的人都知道,mvvm不操作dom,这是框架内部做的事情,而我们仅仅要做的是操作Mode层,也即数据层。
这里我用一个数组存储当前一个月的所有日期对象,每一天就是一个对象,这个对象包括年,月,日,时间戳,是否隶属于当前月等。如下所示:

var caleadar = [
{
year : 2014, // 年份
month : 10, // 月份
date : 1, // 日
time : 1414771200000, // 时间戳
flag : false // 是否隶属于当前月
},
{
year : 2014,
month : 10,
date : 2,
time : 1414911123564,
flag : true
},
.....
];

得到这样一个保存当前月所有信息的数组之后,因为此时caleadar是一个一维数组,而日历是每7天一行,所以这里要将caleadar转化为一个二维数组,每一个子数组里面保存的是一周的日期信息,这样就可以利用avalon的动态模板引擎进行双重模板渲染,这样一个日历就出来了。
利用getWeeks函数我们就可以得到存储有当前月所有日期信息的数组,如下:

function getWeeks(ooo) {
var dateObj = new Date();
var year = ooo.getFullYear();
var month = ooo.getMonth(); //得到今天是几月(0 ~ 11)
var date = ooo.getDate(); //得到今天是几号 (1 ~ 31)
//var cur = new Date(year, month, date);
var cur = new Date(year, month, 1);
cur.setMonth(month + 1); //改为下一个月,
cur.setDate(0);//由于日期是1 ~ 31, 0则是退到上一个月的最后一天,于是得到这个月的总天数
var num = cur.getDate();
var next = 6 - cur.getDay();
var dates = avalon.range(1, num + 1);
dates = dates.map(function(d) {
return dateObj.getFullYear() === year &&
dateObj.getMonth() === month &&
dateObj.getDate() === d ? {
year: year,
month: month,
date: d,
isToday: true,
flag: true,
time: new Date(year, month, d) - 0
} : {
year: year,
month: month,
date: d,
flag: true,
time: new Date(year, month, d) - 0
};
});
cur.setMonth(month);
cur.setDate(1); //得到当月的第一天
var prev = cur.getDay(); //0 ~ 6
cur.setDate(date); //还原
//补上上一个月的日期
if (month - 1 < 0) {
year--;
month = 11;
for (var i = 0; i < prev; i++) {
var curr = new Date(year, month, -1 * i);
dates.unshift({
year: year,
month: month,
date: curr.getDate() + 1,
flag: false,
time: curr - 0
})
}
} else {
for (i = 0; i < prev; i++) {
curr = new Date(year, month, -1 * i);
dates.unshift({
year: year,
month: month - 1,
date: curr.getDate(),
flag: false,
time: curr - 0
})
}
}
//补上下一个月的日期
if (month + 1 == 12) {
year++;
month = 0;
for (i = 0; i < next; i++) {
curr = new Date(year, month, i + 1);
dates.push({
year: year,
month: month,
date: curr.getDate(),
flag: false,
time: curr - 0
})
}
} else {
for (i = 0; i < next; i++) {
curr = new Date(year, month + 1, i + 1);
dates.push({
year: year,
month: month + 1,
date: curr.getDate(),
flag: false,
time: curr - 0
})
}
}
var ret = [];
while (dates.length) {//每行七个分组
ret.push(dates.splice(0, 7));
}
return ret; //一个二维数组
}

这里ooo是getWeeks的唯一参数,它是一个Date对象。
获取到数据之后,直接在html里面进行数据渲染,日历就出来了,相关日历html如下:

<div class="game_calendar" ms-controller="caleadarID">
<div class="current_info">
<button type="button" ms-click="backToToday">today</button>
<button type="button" ms-click="prevMonth">prev</button>
<button type="button" ms-click="nextMonth">next</button>
<span>{{cyear}}年{{cmonth + 1}}月</span>
</div>
<table width="100%" border="0" cellspacing="0" cellpadding="0" class="week_title">
<tbody>
<tr valign="bottom">
<td>日</td>
<td>一</td>
<td>二</td>
<td>三</td>
<td>四</td>
<td>五</td>
<td>六</td>
</tr>
</tbody>
</table>
<table width="100%" cellpadding="0" cellspacing="1" class="calendar_main">
<tbody>
<tr ms-repeat-el="calendar">
<td ms-class="day_style:elem.flag==true" valign="top" ms-repeat-elem="el" ms-click="alert(elem)">
<div class="day_mouse">
<div class="day_no" ms-if="elem.isToday!=true">{{elem.date}}</div>
<div class="day_no" ms-class="today:elem.isToday==true" ms-if="elem.isToday==true">今天</div>
</div>
</td>
</tr>
</tbody>
</table>
</div>

我们可以看到,模板里面运用了大量的以ms-开头的绑定属性和{{}}插值表达式,有的是用来渲染样式,有的是用来绑定事件。这样,一个日历就出来了。
接下来就是日历的切换功能了,实际上上面三个功能本质都是一样,只要传入getWeeks的参数不同返回不同的数组信息就行。因此在程序初始化是我们先保存几个变量,如下:

var dateObj = new Date();
vm.calendar = _private.getWeeks(dateObj); //存储当月日历
vm.cyear = dateObj.getFullYear(); //当前年份
vm.cmonth = dateObj.getMonth(); //当前月份
vm.cdate = dateObj.getDate(); //当前日

接下来就是相关处理逻辑:

//上一个月
vm.prevMonth = function () {
vm.cdate = 1;
--vm.cmonth;
if (vm.cmonth < 0) {
vm.cyear--;
vm.cmonth = 11;
}
_private.change();
}; //下一个月
vm.nextMonth = function () {
vm.cdate = 1;
++vm.cmonth;
if (vm.cmonth == 12) {
vm.cyear++;
vm.cmonth = 0;
}
_private.change();
}; //回到今天
vm.backToToday = function () {
var dateObj = new Date();
vm.cyear = dateObj.getFullYear();
vm.cmonth = dateObj.getMonth();
vm.cdate = dateObj.getDate();
_private.change();
};

改变当前年、月、日后,我们只需要调用change函数来改变caleadar数组,change函数如下:
vm.caleader = _private.getWeeks(new Date(vm.cyear, vm.cmonth, vm.cdate));
这样,一个简易日历就实现了,从头到尾,我们没有操作一行dom,完全的model操作,是不是很爽?
这里为了让大家看到更好的日历效果,附上日历源码,欢迎下载,有任何疑问欢迎留言!
avalon.js实现一个简易日历的更多相关文章
- 使用MVVM框架avalon.js实现一个简易日历
最近在做公司内部的运营管理系统,因为与日历密切相关,同时无需触发条件直接显示在页面上,所以针对这样的功能场景,我就用avalon快速实现了一个简易日历,毕竟也是第一次造日历这种轮子,所以这里记录下我当 ...
- 使用 js 实现一个简易版的模版引擎
使用 js 实现一个简易版的模版引擎 regex (function test() { this.str = str; })( window.Test = ...; format() { let ar ...
- 使用 js 实现一个简易版的 drag & drop 库
使用 js 实现一个简易版的 drag & drop 库 具有挑战性的前端面试题 H5 DnD js refs https://www.infoq.cn/article/0NUjpxGrqRX ...
- 使用 js 实现一个简易版的动画库
使用 js 实现一个简易版的动画库 具有挑战性的前端面试题 animation css refs https://www.infoq.cn/article/0NUjpxGrqRX6Ss01BLLE x ...
- 使用 js 实现一个简易版的 GIPHY 动图搜索 web 应用程序
使用 js 实现一个简易版的 GIPHY 动图搜索 web 应用程序 具有挑战性的前端面试题 API JAMstack refs https://www.infoq.cn/article/0NUjpx ...
- 使用 js 实现一个简易版的 async 库
使用 js 实现一个简易版的 async 库 具有挑战性的前端面试题 series & parallel 串行,并行 refs https://www.infoq.cn/article/0NU ...
- 使用 js 实现一个简易版的 vue 框架
使用 js 实现一个简易版的 vue 框架 具有挑战性的前端面试题 refs https://www.infoq.cn/article/0NUjpxGrqRX6Ss01BLLE xgqfrms 201 ...
- JS写一个简单日历
JS写一个日历,配合jQuery操作DOM <!DOCTYPE html> <html> <head> <meta charset="UTF-8&q ...
- 【html css js】实现一个简易日历
——[效果预览] 实现了日历最基础的功能,当前日期红色显示,可通过上方的左右按钮查看上一月或下一月的日期. ——[代码部分] 1. HTML <body> <div class=&q ...
随机推荐
- hibernate几个纯sql查询
几个hibernate纯SQL询问,查询和表没有映射pojo实体和表有映射关系的实体...... 1.getSession().createSQLQuery(sql).query.addScalar( ...
- 表与表的关系把RD搞乱了,记一个Procedure中的bug
就是6张表的关联查询,写了一个存储过程,使用4层for来处理 bug:最后一个for中,两张表的关联条件少了一个,结果数据多查了. 排查办法:使用dbms_output.printline('');每 ...
- DOS call 中的%cd%,当前文件夹演示
最近的工作要处理.bat文件,在dos文件错综复杂的调用过程中,我迷失了,于是%cd% @echo %cd% @cd %cd%\-- @pause @call %cd%\--\1.bat @pause ...
- Util
Util最新代码更新说明 离上一篇又过去了一个月,时间比较紧,后续估计会更紧,所以这次将放出更多公共操作类及配套的CodeSmith模板,本篇将简要介绍新放出的重要功能,供有兴趣的同学参考. 重要 ...
- SQL Server Log文件对磁盘的写操作大小是多少
原文:SQL Server Log文件对磁盘的写操作大小是多少 SQL Server 数据库有三种文件类型,分别是数据文件.次要数据文件和日志文件,其中日志文件包含着用于恢复数据库的所有日志信息,SQ ...
- 【高德地图API】如何打造十月妈咪品牌地图?
原文:[高德地图API]如何打造十月妈咪品牌地图? 摘要:品牌地图除了地图,商铺标点外,还有微博关注,路线查询等功能. ---------------------------------------- ...
- 进程切换switch_to宏第三个参数分析
进程切换一般都涉及三个进程,如进程a切换成进程b,b开始执行,但是当a恢复执行的时候往往是通过一个进程c,而不是进程b. 注意switch_to的调用: switch_to(prev,next,pre ...
- boost进程间通信经常使用开发一篇全(消息队列,共享内存,信号)
本文概要: 敏捷开发大家想必知道并且评价甚高,缩短开发周期,提高开发质量.将大project独立为不同的小app开发,整个开发过程,程序可用可測,所以提高了总体的质量.基于这样的开发模式和开发理念,进 ...
- springmvc实现long-pulling技术
背景介绍: 项目中有一个通讯模块,本来是用websocket全双工技术实现的,但IE10下面不支持websocket,而国内的360.2345浏 览器封装的所有是IE10下面的内核,考虑到站点在国内的 ...
- ASP.NET MVC 插件化
ASP.NET MVC 插件化机制 2015-03-14 22:25 by 杨康新, 1328 阅读, 15 评论, 收藏, 编辑 概述 nopCommerce的插件机制的核心是使用BuildMana ...