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之十 事件模块概述
Jun 27 Javascript
通过jQuery源码学习javascript(一)
Dec 27 Javascript
jQuery方法简洁实现隔行换色及toggleClass的使用
Mar 15 Javascript
JS清除文本框内容离开在恢复及鼠标离开文本框时触发js的方法
Jan 12 Javascript
xmlplus组件设计系列之列表(4)
Apr 26 Javascript
jquery插件canvaspercent.js实现百分比圆饼效果
Jul 18 jQuery
对layui中表单元素的使用详解
Aug 15 Javascript
Vue实现开心消消乐游戏算法
Oct 22 Javascript
如何在Node和浏览器控制台中打印彩色文字
Jan 09 Javascript
Vue如何实现监听组件原生事件
Jul 03 Javascript
js实现全选和全不选
Jul 28 Javascript
vue中三级导航的菜单权限控制
Mar 31 Vue.js
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
php使用pdo连接报错Connection failed SQLSTATE的解决方法
2014/12/15 PHP
PHP配置ZendOpcache插件加速
2019/02/14 PHP
Laravel框架实现定时Task Scheduling例子
2019/10/22 PHP
js或css实现滚动广告的几种方案
2010/01/28 Javascript
JavaScript 程序编码规范
2010/11/23 Javascript
JavaScript移除数组元素减少长度的方法
2013/09/05 Javascript
jquery表单验证框架提供的身份证验证方法(示例代码)
2013/12/27 Javascript
jquery选择checked在ie8普通模式下的问题
2014/02/12 Javascript
jQuery中:radio选择器用法实例
2015/01/03 Javascript
JS控制网页动态生成任意行列数表格的方法
2015/03/09 Javascript
jQuery使用fadeout实现元素渐隐效果的方法
2015/03/27 Javascript
javascript使用shift+click实现选择和反选checkbox的方法
2015/05/04 Javascript
JavaScript闭包实例详解
2016/06/03 Javascript
用原生JS对AJAX做简单封装的实例代码
2016/07/13 Javascript
微信小程序 参数传递详解
2016/10/24 Javascript
详解js中==与===的区别
2017/01/08 Javascript
如何用webpack4带你实现一个vue的打包的项目
2018/06/20 Javascript
浅析vue中的MVVM实现原理
2019/03/04 Javascript
vue中filters 传入两个参数 / 使用两个filters的实现方法
2019/07/15 Javascript
python shell根据ip获取主机名代码示例
2017/11/25 Python
Python numpy.array()生成相同元素数组的示例
2018/11/12 Python
python3正则提取字符串里的中文实例
2019/01/31 Python
最小二乘法及其python实现详解
2020/02/24 Python
python GUI库图形界面开发之PyQt5 Qt Designer工具(Qt设计师)详细使用方法及Designer ui文件转py文件方法
2020/02/26 Python
Python图片处理模块PIL操作方法(pillow)
2020/04/07 Python
Java程序开发中如何应用线程
2016/03/03 面试题
2014年道德讲堂实施方案
2014/03/05 职场文书
青年文明号创建承诺
2014/03/31 职场文书
幼儿园中班教师寄语
2014/04/03 职场文书
文科毕业生自荐书范文
2014/04/17 职场文书
2013年最新自荐信范文
2014/06/23 职场文书
行政管理专业求职信
2014/07/06 职场文书
民主生活会批评与自我批评总结
2014/10/17 职场文书
海南召开党的群众路线教育实践活动总结大会新闻稿
2014/10/21 职场文书
关于安全的广播稿
2014/10/23 职场文书
党员学习群众路线心得体会
2014/11/04 职场文书