用AJAX自定义日历
需求分析
在一些购物网站中,都会有促销活动,这些活动都在日历上标注出来,如何通过Ajax让日历 通过读取数据库中的信息,正确的把促销活动标注在日历上,本文通过自定义日历来实现这 个问题。
技术难点
- 日历的布局
- 日历的初始化
- 日历的动态变化
- 日历的促销定制
实现方法
1、 先创建一个固定的日历,效果如下

html代码如下
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style type="text/css">
* {margin: 0; padding: 0;}
body {font-size: 13px;}
.calendar {width: 330px; margin: 0 auto;}
.calendar .title {
position: relative;
width: 100%;
height: 30px;
line-height: 30px;
background: #17a4eb;
}
.title div {position: absolute;}
.prev {left: 10px; }
.now {left: 40%;}
.next {right: 10px;}
input {height: 30px; width: 300px; margin: 100px 475px 0px;}
table {width: 100%; border-collapse: collapse;}
table th {border: 1px solid #ccc;}
table td {text-align: center; border: 1px solid #ccc;}
</style>
</head>
<body>
<input type="text">
<div class="calendar">
<div class="title">
<div class="prev">
<span>08</span>月
</div>
<div class="now">
<span>2016</span>年
<span>09</span>月
</div>
<div class="next">
<span>10</span>月
</div>
</div>
<table>
<!--星期部分-->
<thead>
<tr>
<th>日</th>
<th>一</th>
<th>二</th>
<th>三</th>
<th>四</th>
<th>五</th>
<th>六</th>
</tr>
</thead>
<!--日期部分-->
<tbody>
<tr>
<td>1</td>
<td>1</td>
<td>1</td>
<td>1</td>
<td>1</td>
<td>1</td>
<td>1</td>
</tr>
<tr>
<td>1</td>
<td>1</td>
<td>1</td>
<td>1</td>
<td>1</td>
<td>1</td>
<td>1</td>
</tr>
</tbody>
</table>
</div>
</body>
</html>
当创建固定日历后,把日历的html部分注释掉(title和table),保留css部分
2、 通过javascript动态生成日历
window.onload = function () {
var oInput = document.getElementsByTagName('input')[0];
var oCalendar = document.getElementById('calendar');
// console.log(oCalendar);
var oDate = new Date();
var year = oDate.getFullYear();
var month = oDate.getMonth()+1;
//日期td
var oTds = oCalendar.getElementsByTagName('td');
var flag = false;
oInput.onfocus = function () {
showDate(year,month);
}
//显示日历
function showDate(year,month) {
if (false == flag) {
var oTitle = document.createElement('div');
oTitle.className = 'title';
oTitle.innerHTML = '<div class="prev"> <span>'+(month-1)+'</span>月 </div> ' +
'<div class="now"> <span>'+year+'</span>年 <span>'+month+'</span>月 </div> ' +
'<div class="next"> <span>'+(month+1)+'</span>月 </div>';
oCalendar.appendChild(oTitle);
//月份span
ospans = oCalendar.getElementsByTagName('span');
// console.log(ospans);
prevMonth = ospans[0];
nextMonth = ospans[3];
nowMonth = ospans[2];
nowYear = ospans[1];
//创建星期
var otable = document.createElement('table');
var othead = document.createElement('thead');
var otr = document.createElement('tr');
var arr = ['日','一','二','三','四','五','六'];
for (var i=0; i<arr.length; i++) {
//创建th
var oth = document.createElement('th');
oth.innerHTML = arr[i];
otr.appendChild(oth);
}
othead.appendChild(otr);
otable.appendChild(othead);
oCalendar.appendChild(otable);
//先获得当前月有多少天
if (1 == month || 3 == month || 5 == month || 7 == month || 8 == month || 10 == month || 12 == month) {
var dayNum = 31;
} else if (4 == month || 6 == month || 9 == month || 11 == month) {
var dayNum = 30;
} else if (2 == month && isLeapYear(year)) {
var dayNum = 29;
} else {
var dayNum = 28;
}
//确定当前月的1号是星期几
oDate.setFullYear(year);
oDate.setMonth(month-1);
oDate.setDate(1);
//日期
var otbody = document.createElement('tbody');
for (var i=0; i<6; i++) {
var oTr = document.createElement('tr');
//每行里面有7列
for (var j=0; j<7; j++) {
var oTd = document.createElement('td');
//oTd.innerHTML = 1;
oTr.appendChild(oTd);
}
otbody.appendChild(oTr);
}
otable.appendChild(otbody);
//获得今天1号对应的是星期几
var week = oDate.getDay();
var oTds = oCalendar.getElementsByTagName('td');
//alert(week);
for (var i=0; i<dayNum; i++) {
oTds[i+week].innerHTML = i+1;
}
//如果当前月month 是12或者1
if (1 == month) {
prevMonth.innerHTML = 12;
} else if (12 == month) {
nextMonth.innerHTML = 1;
}
//让当前日期显示红色、后面的显示蓝色
showColor();
//给左右月份绑定点击事件
monthEvent();
//给所有的td绑定点击事件
tdClick();
//判断最后一行是否全为空
lastTr();
//获得促销信息
getPromotion();
flag = true;
}
}
//最后一行如果全部为空就将其隐藏
function lastTr() {
//查找最后一行的所有td
var flag = true;
for (var i=35; i<42; i++) {
if (oTds[i].innerHTML != '') {
//有任何一个td不为空就设置为false
flag = false;
}
}
//全部是空的
if (flag) {
for (var i=35; i<42; i++) {
oTds[i].style.display = 'none';
}
}
}
//给所有的td绑定点击事件
function tdClick() {
for (var i=0; i<oTds.length; i++) {
oTds[i].onclick = function() {
if ('red' == this.className ||'blue' == this.className) {
var year = nowYear.innerHTML;
var month = nowMonth.innerHTML;
var date = this.innerHTML;
oInput.value = year +'-'+month+'-'+date;
flag = false;
oCalendar.innerHTML = '';
} else {
alert('您只能选择红色或蓝色区域');
}
}
}
}
//当前日期显示红色、后面的显示蓝色
function showColor() {
//当前的日期
var oday = new Date().getDate();
for (var i=0; i<oTds.length; i++) {
if (oday == oTds[i].innerHTML) {
oTds[i].className = 'red';
var oindex = i;
}
}
for (var j=oindex+1; j<oTds.length; j++) {
oTds[j].className = 'blue';
}
}
//给左右月份绑定点击事件
function monthEvent() {
//向左的月份div
prevMonth.parentNode.onclick = function () {
//alert('向左');
flag = false;
oCalendar.innerHTML = '';
if (12 == prevMonth.innerHTML) {
showDate(year -= 1, 12);
} else {
showDate(year,parseInt(prevMonth.innerHTML));
}
}
//向左的月份div
nextMonth.parentNode.onclick = function () {
//alert('向右');
flag = false;
oCalendar.innerHTML = '';
if (1 == nextMonth.innerHTML) {
showDate(year+=1,1);
} else {
showDate(year,parseInt(nextMonth.innerHTML));
}
}
}
//判断是否是闰年
function isLeapYear(year) {
if (0 == year%100 && 0 == year%400) {
return true;
}else if (year%100 != 0 && year%4 ==0) {
return true;
} else {
return false;
}
}
}
3、 从服务器获取促销的信息并在日历中显示
//从服务器获取促销信息
function getPromotion() {
$.request({
method:"post", //获取方式
url:"promotion.php", //从哪个文件中获取
data:"", //是否传递数据
callback:function (res) {
eval("var obj="+res);
if (obj.status) {
var dates = obj.dates;
for (var i=0; i<dates.length; i++) {
for (var j=0; j<oTds.length; j++) {
if (oTds[j].innerHTML == dates[i]) {
oTds[j].innerHTML += "促销";
oTds[j].style.background = 'red';
}
}
}
}
}
});
}
$.request()是封装在js里的Ajax方法,代码如下:
var $ = {
request:function(obj){
var xhr;
try {
//主流浏览器里面的ajax对象
xhr = new XMLHttpRequest();
} catch(e) {
//IE低版本的浏览器
xhr = new ActiveXObject("Microsoft.XMLHTTP");
}
//建立和服务器的连接
if (obj.method == 'get') {
xhr.open(obj.method,obj.url+'?'+obj.data+'&'+Math.random(),true);
xhr.send();
} else if (obj.method == 'post') {
xhr.open(obj.method,obj.url,true);
xhr.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
xhr.send(obj.data);
}
//监视服务器的处理状态
xhr.onreadystatechange = function(){
if (4 == xhr.readyState && 200 == xhr.status) {
//说明请求成功了,输出服务器返回的数据
obj.callback(xhr.responseText);
}
}
}
}
promotion.php
<?php
$data['status'] = 1;
//促销时间
$data['dates'] = array(28,29,30); echo json_encode($data);
最终效果图如下,样式不是很美观

用AJAX自定义日历的更多相关文章
- javascript实例学习之六—自定义日历控件
基于之前上篇博客轻量级jquery,tool.js和base.js.自定义开发的base_datePicker插件,效果类似于jquery_ui的datePicker插件 //基于Base.js以及t ...
- Springboot如何优雅的解决ajax+自定义headers的跨域请求
1.什么是跨域 由于浏览器同源策略(同源策略,它是由Netscape提出的一个著名的安全策略.现在所有支持JavaScript 的浏览器都会使用这个策略.所谓同源是指,域名,协议,端口相同.),凡是发 ...
- Android自定义日历控件(继承系统控件实现)
Android自定义日历控件(继承系统控件实现) 主要步骤 编写布局 继承LinearLayout设置子控件 设置数据 继承TextView实现有圆圈背景的TextView 添加Attribute 添 ...
- Springboot如何优雅的解决ajax+自定义headers的跨域请求[转]
1.什么是跨域 由于浏览器同源策略(同源策略,它是由Netscape提出的一个著名的安全策略.现在所有支持JavaScript 的浏览器都会使用这个策略.所谓同源是指,域名,协议,端口相同.),凡是发 ...
- ExtJS基础知识总结:自定义日历和ComboBox控件(二)
概述 1.ExtJS 5不支持日期选择框中只选择年月,为了满足ExtJs5可以实现选择年月的功能,查询网上资料,整理出来了相应的处理方式,最终实现的效果如下图: 2.ExtJS 控件丰富,如果需要实现 ...
- 用NSCalendar和UICollectionView自定义日历,并实现签到显示
前一段时间因为工作需要实现了一个可以签到的日历,来记录一下实现的思路 效果如图: 这里的基本需求是: 1,显示用户某个月的签到情况,已经签到的日子打个圈,没有签到且在某个时间范围内的可以签到,其他 ...
- IOS自定义日历控件的简单实现(附思想及过程)
因为程序要求要插入一个日历控件,该空间的要求是从当天开始及以后的六个月内的日历,上网查资料基本上都说只要获取两个条件(当月第一天周几和本月一共有多少天)就可以实现一个简单的日历,剩下的靠自己的简单逻辑 ...
- 利用 ajax自定义Form表单的提交方式
需求场景:有时候单纯的form表单无法向后端传递额外的参数 比如需要action传递js异步生成的参数 ,form表单默认的action就无法满足需求,这时就需要我们自定义form表单的提交方式. h ...
- ✅问题:Rails.ajax自定义请求
chatroom.coffee中的js代码: document.addEventListener 'turbolinks:load', -> document.getElementById(&q ...
随机推荐
- Linux 引导过程内幕
转载:http://www.ibm.com/developerworks/cn/linux/l-linuxboot/index.html 从主引导记录到第一个用户空间应用程序的指导 引导 Linu ...
- eclipse 的小技巧
1. ctrl+o:快速outline 如果想要查看当前类的方法或某个特定方法,但又不想把代码拉上拉下,也不想使用查找功能的话,就用ctrl+o吧.它可以列出当前类中的所有方法及属性,你只需输入你想要 ...
- 由c#的值类型与引用类型说开去
之前一直被灌输,C#分值类型和引用类型,在程序运行时,它们分别存在栈(Stack) 和堆(Heap)上.这也是面试经典问题了,但其实其中存在很大的误解.比如某个实例对象中有一个Int型成员.当这个实例 ...
- 把旧的项目改变名称重新部署到tomcat下发现项目名称还是原来的项目名称,解决方案
选中项目右键点击properties 在type file text 中输入web 选择web在右边可以看到web-context-root 把里面的项目名称改成你最新的就ok了
- oracle顺序控制语句goto、null和分页过程中输入输出存储、java程序的调用过程
顺序控制语句1 goto建议不要使用 declare i number:=; begin loop dbms_output.put_line(i); then goto end_loop; end i ...
- CF Tavas and Nafas
Tavas and Nafas time limit per test 1 second memory limit per test 256 megabytes input standard inp ...
- Eclipse 中引用其他项目及项目打包
1.建立工程project1; 2.建立class文件ClassA: package com.test; public class ClassA{ public static String getCl ...
- poj 1848 树形dp
思路:表示我很弱,这个想不出dp方程,参考网上代码 #include<iostream> #include<algorithm> #include<cstring> ...
- hdu 2852 树状数组
思路:加一个数e就用update(e,1).删除元素e就用update(e,-1).找比a大的第k大的元素就用二分查找. #include<iostream> #include<cs ...
- Android自动化测试介绍
1.随机事件测试.通过adb命令执行测试Monkey 就是SDK中附带的一个工具, 用来做压力测试.应用程序crash 和 ANR时会产生日志. 然后根据关键字分析,就可以把应用出现的问题抓出来. 2 ...