js前端日历控件(悬浮、拖拽、自由变形)


Posted in Javascript onMarch 02, 2017

很少发现网上有简洁好用的自定义前端控件的贴子,最近项目中需要,自己YY开始写前端控件,在此给大家分享

控件是基于jQuery.UI的Widget写的,写起来就方便很多,使用起来跟普通jQuery控件一样$(#id).control(option),看着眼熟吧,下面就开始了。

首先说下控件的依赖包,加载控件的时候必须先加载jQuery, jQuqery.UI, 另外jquery-ui.css

这个包也需要引用,此包主要应用了jQuery拖拽和放缩的样式,控件样式方面大家自由发挥,给了个自己写的默认样式包 (献丑了)。 

控件本身支持颜色自定义,可根据日期自定义日历上某日的颜色,另外可悬浮,拖拽,自由变形算是卖点吧,哈哈 

控件包加载是这样的:

<link href="../../Content/themes/base/jquery-ui.css" rel="stylesheet" />
<link href="../../Content/datePrinter.css" rel="stylesheet" />

<script src="../../Scripts/default/jquery-ui-1.8.20.min.js"></script>
<script src="../../Scripts/control/datePrinter.js"></script>

控件中的核心部分就是打印选中月的日历,是参考网上的代码,偷懒嘛,欢迎认领

例如页面代码如下:

<input type="text" id="datepickerInput"/>

调用的写法:

var dpCon = $("#datepickerInput").datePrinter({
   initDate: "2017-4-5", //初始化日期
   language: "EN", //语言
   resizable: true, //可自由变形
   draggable: true, //可悬浮拖拽
   showYearAndMonth: true, //是否显示年月下拉框
   getColor: getColor, //自定义颜色接口
   chooseDone: chooseDone //选中日历某日执行事件接口
  });

  //选中日期时让日历消失 当然此处可以执行比较复杂的业务,如服务器数据请求
  function chooseDone(date) {
   dpCon.datePrinter("dpHide");
  }

  //自定义日期颜色
  function getColor(day){
   if(day == 3 || day==7 || day==15)
    return "dpdisabled";
   else if(day== 5 || day==18 || day==23)
    return "dpyellow";
   else
    return "dpenable";
  }

  //获取当前选中的日期 调用控件提供的API getSelectDate
  dpCon.datePrinter("getSelectDate");

这样子就给上面的input text控件注册了一个日历控件,在点击input时,日历就会浮出,效果如下

js前端日历控件(悬浮、拖拽、自由变形)

你可能注意到右下角的小三角了,鼠标放上去之后可以随意变化日历的长宽,另外在日历上按住鼠标左键可以随意移动日期控件的位置,不挤占页面位置

js前端日历控件(悬浮、拖拽、自由变形)

 下面这段是打印日历的代码,供参考:

//默认获取当前日期
  var today = option.initDate ? option.initDate : new Date();
  this.options.initDate = today;
  //获取日期中的年份
  var y = today.getFullYear(),
  //获取日期中的月份(需要注意的是:月份是从0开始计算,获取的值比正常月份的值少1)
  m = today.getMonth(),
  //获取日期中的日(方便在建立日期表格时高亮显示当天)
  d = today.getDate(),
  //获取当月的第一天
  firstday = new Date(y, m, 1),
  //判断第一天是星期几(返回[0-6]中的一个,0代表星期天,1代表星期一,以此类推)
  dayOfWeek = firstday.getDay() == 0 ? 7 : firstday.getDay(),
  //创建月份数组
  days_per_month = new Array(31, 28 + self._isLeap(y), 31, 30, 31, 30, 31, 31, 30, 31, 30, 31),
  //确定日期表格所需的行数
  str_nums = Math.ceil((dayOfWeek + days_per_month[m] - 1) / 7);
  //二维数组创建日期表格
  for (i = 0; i < str_nums; i += 1) {
   var tr = '<tr>';
   for (k = 0; k < 7; k++) {
    //为每个表格创建索引,从0开始
    var idx = 7 * i + k;
    //将当月的1号与星期进行匹配
    var day = idx - dayOfWeek +2;
    var styleName = self._getColor(day);
    if (option.getColor && typeof (option.getColor) == 'function')
     styleName = option.getColor(day);
    styleName += " dateTD";

    (day <= 0 || day > days_per_month[m]) ?
    //索引小于等于0或者大于月份最大值就用空表格代替
    (day = ' ', styleName = "dpBlank") : (day = idx - dayOfWeek + 2);
    day == d ? tr += '<td class="' + styleName + ' today">' + day + '</td>' :
    //高亮显示当天
    tr += '<td class="' + styleName + '">' + day + '</td>';
   }
   tr += '</tr>';
   self._dpTable.append(tr);
   tr = "";
  }

以前都是写后台,玩前端的时间不长,有不对的地方欢迎指正

datePrinter.js的全部代码如下:

var _datePrinter_tmpl_CN = "<tr><th>一</th><th>二</th><th>三</th><th>四</th><th>五</th><th>六</th><th>日</th></tr>";
var _datePrinter_tmpl_EN = "<tr><th>Mon</th><th>Tue</th><th>Wed</th><th>Thu</th><th>Fri</th><th>Sat</th><th>Sun</th></tr>";

Date.prototype.Format = function (fmt) { //author: meizz 
 var o = {
 "M+": this.getMonth() + 1,   //月份 
 "d+": this.getDate(),   //日 
 "h+": this.getHours(),   //小时 
 "m+": this.getMinutes(),   //分 
 "s+": this.getSeconds(),   //秒 
 "q+": Math.floor((this.getMonth() + 3) / 3), //季度 
 "S": this.getMilliseconds()  //毫秒 
 };
 if (/(y+)/.test(fmt))
 fmt = fmt.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length));
 for (var k in o)
 if (new RegExp("(" + k + ")").test(fmt))
  fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)));
 return fmt;
}

$.widget("ui.datePrinter", {
 options: {
 initDate: null,
 language: null, // CN,EN
 resizable: false,
 draggable: false,
 width: "240px",
 dateFormat:'yyyy/MM/dd',
 getColor: null, //自定义颜色
 showYearAndMonth: false,
 chooseDone: function (selectDate) { return selectDate }, //选中日期后执行的自定义事件
 autoId:null //控件Id
 },
 _dpTable: null,
 _dpRoot:null,
 _selectDate:null, //选中日期
 _create: function () {
 var self = this, option = this.options, ele = this.element;
 $(ele).after("<div class='dpRoot'></div>");
 self._dpRoot = $(ele).parent().find('div.dpRoot');
 self._dpRoot.empty();

 self._dpRoot.append("<div class='dpTitle' style='text-align:right;background-color:#e8edf4; width:" + option.width +
  "'><select class='selYear'></select><select class='selMonth'></select><a style='color:#000;text-decoration:none;font-size:18px;padding-left:10px; padding-right:10px;width:10px;' href='javascript:void(0);'>x</a></div>");
 self._dpRoot.append("<table style='width:" + option.width + "' cellspacing='0'></table>");
 option.autoId = self._newGuid();
 },
 _init: function () {
 var self = this, option = this.options, ele = this.element;
 if (option.initDate && typeof option.initDate == 'string')
  option.initDate = new Date(option.initDate.replace("-", "/"));

 //初始化日历
 self._initDate();

 //点击事件
 self._dpTable.delegate("td", "click", function () {
  if (!$(this).hasClass("dpBlank")) {
  self._dpTable.find("td").removeClass("today");
  $(this).addClass("today");
  //控件设置值
  $.proxy(self._setDate($(this).text()), self);

  if (option.chooseDone && typeof (option.chooseDone) == 'function')
   $.proxy(option.chooseDone(self._selectDate), self);
  }
 });

 if (option.resizable)
  self._dpRoot.resizable({
  minHeight: self._dpRoot.css("height").replace("px",''),
  minWidth:option.width.replace("px",''),
  resize: function (event, ui) {
   var titleHeight = self._dpRoot.find("div.dpTitle").css("height").replace("px", "");

   //最小值时不再缩小
   if (ui.size.width >= Number(option.width.replace("px",''))) {
   $(ui.element).find("table").css({ "width": ui.size.width, "height": ui.size.height - titleHeight, "text-align": "center" });
   $(ui.element).find("div.dpTitle").css({ "width": ui.size.width });
   }
  }
  });

 if(option.draggable)
  self._dpRoot.draggable();

 //关闭按钮事件
 self._dpRoot.find("div.dpTitle > a").bind("click", function () {
  $.proxy(self.dpHide(), self);
 });

 if (option.showYearAndMonth) {
  self._initSelYear();
  self._initSelMonth();
 }

 $(ele).focus(function () {
  self.dpShow();
 });

 $(ele).click(function () {
  self.dpShow();
 });

 //$(ele).blur(function (e) {
 // if ($(e.target).closest('div.dpRoot').length == 0) {
 // self.dpHide();
 // }
 //});
 },

 _destroy: function () {
 var self = this, option = this.options, ele = this.element;
 self._dpRoot.empty();
 this._prototype._destroy.call(self);
 },

 _getColor: function (date) {
 var styleName = null;
 if (date == 3 || date == 5 || date == 12)
  styleName = "dpdisabled";
 else if (date == 20 || date == 23 || date == 27)
  styleName = "dpyellow";
 else
  styleName = "dpenable";

 return styleName;
 },

 _initSelYear: function () {
 var self = this, option = this.options, ele = this.element;
 //根据初始化设置时间计算
 var today = option.initDate ? option.initDate : new Date();
 this.options.initDate = today;
 var y = today.getFullYear(),
 m = today.getMonth();

 //打印年 + - 10
 for (var i = 0; i < 20; i++) {
  var varSel = (y == (y + i - 10)) ? "selected='selected'" : "";
  self._dpRoot.find("select.selYear").show().append("<option value='" + (y + i - 10) + "' " + varSel + ">" + (y + i - 10) + "</option");
 }

 //年事件
 self._dpRoot.find("select.selYear").bind("change", function () {
  option.initDate = new Date(option.initDate.setYear($(this).val()));
  self._initDate();
 });
 },

 _initSelMonth: function () {
 var self = this, option = this.options, ele = this.element;
 //根据初始化设置时间计算
 var today = option.initDate ? option.initDate : new Date();
 this.options.initDate = today;
 var y = today.getFullYear(),
 m = today.getMonth();
 //打印月
 for (var i = 0; i < 12; i++) {
  var varSel = (m == i) ? "selected='selected'" : "";
  self._dpRoot.find("select.selMonth").show().append("<option value='" + (i + 1) + "' " + varSel + ">" + (i + 1) + "</option");
 }

 //月事件
 self._dpRoot.find("select.selMonth").bind("change", function () {
  var selMon = Number($(this).val()) - 1;
  option.initDate = new Date(option.initDate.setMonth(selMon));
  self._initDate();
 });
 },

 _initDate: function () {
 var self = this, option = this.options, ele = this.element;

 self._dpTable = self._dpRoot.find("table");
 self._dpTable.empty();
 if (option.language == "EN") {
  self._dpTable.wrapInner(_datePrinter_tmpl_EN);
 }

 //默认获取当前日期
 var today = option.initDate ? option.initDate : new Date();
 this.options.initDate = today;
 //获取日期中的年份
 var y = today.getFullYear(),
 //获取日期中的月份(需要注意的是:月份是从0开始计算,获取的值比正常月份的值少1)
 m = today.getMonth(),
 //获取日期中的日(方便在建立日期表格时高亮显示当天)
 d = today.getDate(),
 //获取当月的第一天
 firstday = new Date(y, m, 1),
 //判断第一天是星期几(返回[0-6]中的一个,0代表星期天,1代表星期一,以此类推)
 dayOfWeek = firstday.getDay() == 0 ? 7 : firstday.getDay(),
 //创建月份数组
 days_per_month = new Array(31, 28 + self._isLeap(y), 31, 30, 31, 30, 31, 31, 30, 31, 30, 31),
 //确定日期表格所需的行数
 str_nums = Math.ceil((dayOfWeek + days_per_month[m] - 1) / 7);
 //二维数组创建日期表格
 for (i = 0; i < str_nums; i += 1) {
  var tr = '<tr>';
  for (k = 0; k < 7; k++) {
  //为每个表格创建索引,从0开始
  var idx = 7 * i + k;
  //将当月的1号与星期进行匹配
  var day = idx - dayOfWeek +2;
  var styleName = self._getColor(day);
  if (option.getColor && typeof (option.getColor) == 'function')
   styleName = option.getColor(day);
  styleName += " dateTD";

  (day <= 0 || day > days_per_month[m]) ?
  //索引小于等于0或者大于月份最大值就用空表格代替
  (day = ' ', styleName = "dpBlank") : (day = idx - dayOfWeek + 2);
  day == d ? tr += '<td class="' + styleName + ' today">' + day + '</td>' :
  //高亮显示当天
  tr += '<td class="' + styleName + '">' + day + '</td>';
  }
  tr += '</tr>';
  self._dpTable.append(tr);
  tr = "";
 }
 },

 _isLeap: function (year) {
 var self = this, option = this.options, ele = this.element;
 return year % 4 == 0 ? (year % 100 != 0 ? 1 : (year % 400 == 0 ? 1 : 0)) : 0;
 },

 //选中日期时设置选中值 day为currentDate当月的第几日
 _setDate: function (day) {
 var self = this, option = this.options, ele = this.element;
 self._selectDate = new Date(option.initDate.getFullYear() + '/' + (option.initDate.getMonth() + 1) + '/' + day);
 //设置输入框值
 $(ele).val(self.getSelectDate(), self);
 },

 //获取所选日期
 getSelectDate: function () {
 var self = this, option = this.options, ele = this.element;
 return self._selectDate.Format(option.dateFormat);
 },

 //显示
 dpShow: function () {
 var self = this, option = this.options, ele = this.element;
 self._dpRoot.show();
 },
 
 //隐藏
 dpHide: function () {
 var self = this, option = this.options, ele = this.element;
 self._dpRoot.hide();
 },

 //new Guid
 _newGuid: function () {
 var guid = "";
 for (var i = 1; i <= 32; i++) {
  var n = Math.floor(Math.random() * 16.0).toString(16);
  guid += n;
  if ((i == 8) || (i == 12) || (i == 16) || (i == 20)) {
  //guid += "-";
  }
 }
 return guid;
 }

});

样式本人是业余的,勉强看看吧,由于datePrinter.js有依赖css的class名称,贴出来datePrinter.css文件代码如下

.dpBlank {
 background-color: white;
 cursor: not-allowed;
}


.dpRoot {
 width: 240px;
 position:absolute;
 display:none;
}

.today {
 border: 2px double #FF9900 !important;
}

.dpenable {
 background-color: #AABBFF;
}

.dpyellow {
 background-color: #FFC266;
}

.dpdisabled {
 background-color: #B0AEA4;
}

.dpRoot table {
 font-size: 13px;
 width: inherit;
}

.dpRoot table th {
 font-size: 12px;
 border: solid 2px #e8eef4;
 padding: 2px 3px;
 background-color: #e8eef4;
 border-collapse:initial;
 text-align: center;
 width: 22px;
}

.dpRoot table td {
 color: white;
 padding: 4px 5px;
 border: solid 2px #e8eef4;
}

.dpTitle {
 padding: 3px 0 0 0;
}

.dateTD {
 cursor: pointer;
}

.selYear {
 margin-right: 5%;
 display: none;
 font-size:14px;
}

.selMonth {
 margin-right: 5%;
 display: none;
 font-size:14px;
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
关于jquery ajax 调用带参数的webservice返回XML数据一个小细节
Jul 31 Javascript
谷歌浏览器不支持showModalDialog模态对话框的解决方法
Sep 22 Javascript
jQuery扁平化风格下拉框美化插件FancySelect使用指南
Feb 10 Javascript
JS实现鼠标点击展开或隐藏表格行的方法
Mar 03 Javascript
javascript常用的方法整理
Aug 20 Javascript
分享jQuery封装好的一些常用操作
Jul 28 Javascript
angularjs实现过滤并替换关键字小功能
Sep 19 Javascript
vue的mixins属性详解
Mar 14 Javascript
angular 实时监听input框value值的变化触发函数方法
Aug 31 Javascript
微信小程序按钮点击跳转页面详解
May 06 Javascript
antdesign-vue结合sortablejs实现两个table相互拖拽排序功能
Jan 08 Vue.js
利用js实现简单开关灯代码
Nov 23 Javascript
JS操作input标签属性checkbox全选的实现代码
Mar 02 #Javascript
JavaScript正则获取地址栏中参数的方法
Mar 02 #Javascript
原生js仿浏览器滚动条效果
Mar 02 #Javascript
使用grunt合并压缩js和css文件的方法
Mar 02 #Javascript
Angular-Ui-Router+ocLazyLoad动态加载脚本示例
Mar 02 #Javascript
浅谈Vue.js
Mar 02 #Javascript
利用imgareaselect辅助后台实现图片上传裁剪
Mar 02 #Javascript
You might like
Snoopy类使用小例子
2008/04/15 PHP
用php来改写404错误页让你的页面更友好
2013/01/24 PHP
PHP实现原比例生成缩略图的方法
2016/02/03 PHP
图文详解PHP环境搭建教程
2016/07/16 PHP
PHP实现支持加盐的图片加密解密
2016/09/09 PHP
PHP的简单跳转提示的实现详解
2019/03/14 PHP
Javascript String.replace的妙用
2009/09/08 Javascript
JQuery操作tr和td内容的方法实例
2013/03/06 Javascript
使用indexOf等在JavaScript的数组中进行元素查找和替换
2013/09/18 Javascript
JavaScript获取当前网页标题(title)的方法
2015/04/03 Javascript
AngularJS基础教程之简单介绍
2015/09/27 Javascript
javascript移动开发中touch触摸事件详解
2016/03/18 Javascript
nodejs socket服务端和客户端简单通信功能
2017/09/14 NodeJs
vue 指定组件缓存实例详解
2018/04/01 Javascript
js实现文件上传功能 后台使用MultipartFile
2018/09/08 Javascript
谈谈为什么你的 JavaScript 代码如此冗长
2019/01/30 Javascript
浅析JavaScript异步代码优化
2019/03/18 Javascript
JS常用跨域方法实现原理解析
2020/12/09 Javascript
让Python代码更快运行的5种方法
2015/06/21 Python
Python实现以时间换空间的缓存替换算法
2016/02/19 Python
Python实现从log日志中提取ip的方法【正则提取】
2018/03/31 Python
PyQt5每天必学之像素图控件QPixmap
2018/04/19 Python
Python中交换两个元素的实现方法
2018/06/29 Python
python shell命令行中import多层目录下的模块操作
2020/03/09 Python
Python datetime 如何处理时区信息
2020/09/02 Python
html5中使用hotcss.js实现手机端自适配的方法
2020/04/23 HTML / CSS
乌克兰排名第一的在线旅游超市:Farvater.Travel
2020/01/02 全球购物
eDreams德国:南欧领先的在线旅游公司
2020/12/07 全球购物
环境工程大学生个人的自我评价
2013/10/08 职场文书
村官工作鉴定评语
2014/01/27 职场文书
职工趣味运动会方案
2014/02/10 职场文书
党员四风问题对照检查材料思想汇报
2014/09/16 职场文书
小学生作文批改评语
2014/12/25 职场文书
2015年清明节网上祭英烈留言寄语
2015/03/04 职场文书
投标单位介绍信
2015/05/05 职场文书
详解Flutter和Dart取消Future的三种方法
2022/04/07 Java/Android