需求分析

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

    Description In the game of DotA, Pudge’s meat hook is actually the most horrible thing for most of t ...

  2. gulp构建工具的安装

    第一步:node.js安装 在gulp安装之前,本机需要node环境.访问http://nodejs.org,然后点击大大的绿色的install按钮,下载完成后直接运行程序.npm会随着安装包一起安装 ...

  3. nginx实现域名重定向

    一般网站默认的访问端口为80,当多个域名指向同一个服务器IP时,可以nginx进行重定向,分别指向不同的目的地址或其他主机. 在nginx目录下的conf/vhost子目录下建两个conf文件,hos ...

  4. js验证 button 提交

    <form class="form-horizontal" role="form" action="member_add" metho ...

  5. css3 盒模型记

    css3 盒模型 css假定每个元素都会生成一个或多个矩形框,这称为元素框.各元素框中心有一个内容区.这个内容区周围有可选的内边距,边框和外边距.这些项之所以被认为是可选的,原因是它们的宽度可以设置为 ...

  6. 自定义表单样式之checkbox和radio

    1,起因 最近在工作中要实现自定义式的radio样式,而我们通常使用的时默认的样式,因为自己实在想不到解决的方法,于是开始搜索,最终看到了不错的解决办法,可以完美解决我们遇到的问题. 2,原理 大家都 ...

  7. framework7学习笔记

    最近因项目需要学习framework7,简称F7.对于自己遇到的问题和学习到的东西做个简单记录. 问题:刚开始获取json,页面上一直不显示,不得其法,原来是json文件需要在弹出层打开之后在来加载, ...

  8. Spring(3.2.3) - Beans(8): 基于 Annotation 的配置

    除了基于 XML 的配置外,Spring 也支持基于 Annotation 的配置.Spring 提供以下介个 Annotation 来标注 Spring Bean: @Component:标注一个普 ...

  9. Jquery EasyUI的datagrid页脚footer使用及数据统计

    最近做一个统计类的项目中遇到datagrid数据显示页脚footer合计的问题,对于构造统计结果数据格式,是在程序端构造一个{"rows":[],"total" ...

  10. Android Studio工程目录介绍

    来自知乎: Android Studio工程目录结构 .gradle 是gradle运行以后生成的缓存文件夹. .idea 是android studio/Intellij IDEA工程打开以后生成的 ...