需求分析

在一些购物网站中,都会有促销活动,这些活动都在日历上标注出来,如何通过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);

最终效果图如下,样式不是很美观

代码托管于GitHub

用AJAX自定义日历的更多相关文章

  1. javascript实例学习之六—自定义日历控件

    基于之前上篇博客轻量级jquery,tool.js和base.js.自定义开发的base_datePicker插件,效果类似于jquery_ui的datePicker插件 //基于Base.js以及t ...

  2. Springboot如何优雅的解决ajax+自定义headers的跨域请求

    1.什么是跨域 由于浏览器同源策略(同源策略,它是由Netscape提出的一个著名的安全策略.现在所有支持JavaScript 的浏览器都会使用这个策略.所谓同源是指,域名,协议,端口相同.),凡是发 ...

  3. Android自定义日历控件(继承系统控件实现)

    Android自定义日历控件(继承系统控件实现) 主要步骤 编写布局 继承LinearLayout设置子控件 设置数据 继承TextView实现有圆圈背景的TextView 添加Attribute 添 ...

  4. Springboot如何优雅的解决ajax+自定义headers的跨域请求[转]

    1.什么是跨域 由于浏览器同源策略(同源策略,它是由Netscape提出的一个著名的安全策略.现在所有支持JavaScript 的浏览器都会使用这个策略.所谓同源是指,域名,协议,端口相同.),凡是发 ...

  5. ExtJS基础知识总结:自定义日历和ComboBox控件(二)

    概述 1.ExtJS 5不支持日期选择框中只选择年月,为了满足ExtJs5可以实现选择年月的功能,查询网上资料,整理出来了相应的处理方式,最终实现的效果如下图: 2.ExtJS 控件丰富,如果需要实现 ...

  6. 用NSCalendar和UICollectionView自定义日历,并实现签到显示

    前一段时间因为工作需要实现了一个可以签到的日历,来记录一下实现的思路 效果如图:   这里的基本需求是: 1,显示用户某个月的签到情况,已经签到的日子打个圈,没有签到且在某个时间范围内的可以签到,其他 ...

  7. IOS自定义日历控件的简单实现(附思想及过程)

    因为程序要求要插入一个日历控件,该空间的要求是从当天开始及以后的六个月内的日历,上网查资料基本上都说只要获取两个条件(当月第一天周几和本月一共有多少天)就可以实现一个简单的日历,剩下的靠自己的简单逻辑 ...

  8. 利用 ajax自定义Form表单的提交方式

    需求场景:有时候单纯的form表单无法向后端传递额外的参数 比如需要action传递js异步生成的参数 ,form表单默认的action就无法满足需求,这时就需要我们自定义form表单的提交方式. h ...

  9. ✅问题:Rails.ajax自定义请求

    chatroom.coffee中的js代码: document.addEventListener 'turbolinks:load', -> document.getElementById(&q ...

随机推荐

  1. discuz常用变量

    帖子URL: {url}帖子标题: {title}附件图片: {pic}帖子内容: {summary}楼主: {author}楼主UID: {authorid}楼主头像: {avatar}楼主头像(中 ...

  2. vim中taglist使用

    转载:http://www.cnblogs.com/mo-beifeng/archive/2011/11/22/2259356.html 本节所用命令的帮助入口: :help helptags :he ...

  3. uva 133 The Dole Queue 双向约瑟夫环 模拟实现

    双向约瑟夫环. 数据规模只有20,模拟掉了.(其实公式我还是不太会推,有空得看看) 值得注意的是两个方向找值不是找到一个去掉一个,而是找到后同时去掉. 还有输出也很坑爹! 在这里不得不抱怨下Uva的o ...

  4. Active Session History (ASH) Performed An Emergency Flush Messages In The Alert Log

    Active Session History (ASH) Performed An Emergency Flush Messages In The Alert Log (文档 ID 1385872.1 ...

  5. DedeCMS更新文章同步发布到新浪微博

    如果在网站推广过程中能利用好微博这个工具的话,将会给网站的推广工作带来巨大的便利.下面以dede程序为例讲讲如何将网站内容自动同步到新浪微博. 在新浪微博的工具中有个自动关联博客的功能,利用好这个功能 ...

  6. [改善Java代码]构造代码块会想你所想

    建议37: 构造代码块会想你所想 镜像博文:http://www.cnblogs.com/DreamDrive/p/5413408.html http://www.cnblogs.com/DreamD ...

  7. 【二分查找最优解】FZU 2056 最大正方形

    题意:现在有一个n*m的矩阵A,在A中找一个H*H的正方形,使得其面积最大且该正方形元素的和不大于 limit. 分析:开始以为是DP或者二维RMQ,其实用二分就可以做出来: 在输入时构造元素和矩阵d ...

  8. Codevs 2307[SDOI2009]HH的项链

    同题:     Codevs 2307 HH的项链     BZOJ    1878 HH的项链     洛谷      1972 HH的项链 2009年省队选拔赛山东  时间限制: 1 s  空间限 ...

  9. jQuery对象和dom对象的辨析和相互转化

    jquery对象和dom对象总是让人感觉很难分清,其实只要做到1对两者概念有明确认识2找出不同点 A DOM 1概念 DOM对象(Document Object Model,文档对象模型)可以把htm ...

  10. SignalR 2.0 系列:SignalR的服务器广播

    英文渣水平,大伙凑合着看吧…… 这是微软官方SignalR 2.0教程Getting Started with ASP.NET SignalR 2.0系列的翻译,这里是第八篇:SignalR的服务器广 ...