Prologue . Bug And Analysis
开心就好~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^_^
写这篇文章助助兴,调剂下最近繁重的工作。是的,我现在化身成一个打杂的。
最近项目准备上线,系统稳定性和业务逻辑稳定性逐步提升后,可爱的小测试提出一个惊为天人的二类BUG——
Bootstrap页面框架的时间选择框选择困难!
作为一只萌萌哒后台狗,这种疑难杂症一般解决思路是:不予解决。
可是架构师让我顺便仔细考虑下此问题,尽量不去切换页面组件。T.T
好吧~~~那首先让我们首先分析下问题!这是Datetimepicker官方给出的示例。
当页面当前位置在靠近下端时,选择框向下弹出:
妹!子!说!她!选!的!很!不!舒!服!
炸裂=。=
好吧看看我能做什么。T.T
Chapter one . Purpose
预设目标:
1. Datetimepicker时间选择框尽量放弃使用累赘的页面配置(我初步设想是通过css样式控制。)提高开发效率。
2. 当选择框在页面上部时,往下弹出。反之往上弹出。
3. 当输入框为只读时,去掉禁止输入的悬停事件手势。(这是顺便解决的另外一个BUG=。=)
Chapter two . Used Source Code
Bootstrap是一款推特公司推出的页面开发框架。许多运营商都为它提供了js组件,比如页面验证,树,选择器,富文本等等等。
Bootstrap的核心理念是将扁平式交互设计并将终端屏幕分为12等分。我们这里讲的是它的一个常用的时间选择器datetimepicker。
在页面上使用datetimepicker我们一般需要这样搞:
HTML:
1 <div class="form-group"> 2 <label class="col-sm-2 control-label" for="dtp_input2"> 3 海贼王下次多会断更: 4 <span style="color: red;">*</span> 5 </label> 6 <div class="col-md-10"> 7 <div class="input-group date col-sm-5 "> 8 <input id="date1" class="form-control" type="text" size="16" readonly=readonly 9 value="<fmt:formatDate value="${date}" pattern="yyyy-MM-dd HH:mm"/>" /> 10 <span class="input-group-addon"><span class="glyphicon glyphicon-remove"></span></span> 11 <span class="input-group-addon"><span class="glyphicon glyphicon-calendar"></span></span> 12 </div> 13 </div> 14 </div>
备注:页面需要声明JS CSS引用。
JS:
1 $("#date1").datetimepicker({ 2 language : 'zh-CN', 3 format : "yyyy-mm-dd hh:ii", 4 todayBtn : 1, autoclose : 1, 5 todayHighlight : 1, 6 startDate : (new Date()).formate("yyyy-MM-dd HH:mm"), 7 pickerPosition : 'bottom-right' 8 });
这里使用了(new Date()).formate("yyyy-MM-dd HH:mm")是对JS原型Date对象formate()方法的的一个简单原型拓展。
1 /** 2 * JS原型初始化拓展 3 */ 4 var formatPrototype = function() { 5 ... 6 /** 7 * 对Date的扩展,将 Date 转化为指定格式的String 8 * 月(M)、日(d)、12小时(h)、24小时(H)、分(m)、秒(s)、周(E)、季度(q) 可以用 1-2 个占位符 年(y)可以用 1-4 9 * 个占位符,毫秒(S)只能用 1 个占位符(是 1-3 位的数字) eg: (new Date()).formate("yyyy-MM-dd 10 * hh:mm:ss.S") ==> 2006-07-02 08:09:04.423 (new Date()).formate("yyyy-MM-dd 11 * E HH:mm:ss") ==> 2009-03-10 二 20:09:04 (new Date()). formate("yyyy-MM-dd 12 * EE hh:mm:ss") ==> 2009-03-10 周二 08:09:04 (new Date()).formate("yyyy-MM-dd 13 * EEE hh:mm:ss") ==> 2009-03-10 星期二 08:09:04 (new Date()).formate("yyyy-M-d 14 * h:m:s.S") ==> 2006-7-2 8:9:4.18 15 */ 16 Date.prototype.formate = function(fmt) { 17 var o = { 18 "M+" : this.getMonth() + 1, // 月份 19 "d+" : this.getDate(), // 日 20 "h+" : this.getHours() % 12 == 0 ? 12 : this.getHours() % 12, // 小时 21 "H+" : this.getHours(), // 小时 22 "m+" : this.getMinutes(), // 分 23 "s+" : this.getSeconds(), // 秒 24 "q+" : Math.floor((this.getMonth() + 3) / 3), // 季度 25 "S" : this.getMilliseconds() 26 // 毫秒 27 }; 28 var week = { 29 "0" : "u65e5", 30 "1" : "u4e00", 31 "2" : "u4e8c", 32 "3" : "u4e09", 33 "4" : "u56db", 34 "5" : "u4e94", 35 "6" : "u516d" 36 }; 37 if (/(y+)/.test(fmt)) { 38 fmt = fmt.replace(RegExp.$1, (this.getFullYear() + "") 39 .substr(4 - RegExp.$1.length)); 40 } 41 if (/(E+)/.test(fmt)) { 42 fmt = fmt 43 .replace( 44 RegExp.$1, 45 ((RegExp.$1.length > 1) ? (RegExp.$1.length > 2 ? "u661fu671f" 46 : "u5468") 47 : "") 48 + week[this.getDay() + ""]); 49 } 50 for ( var k in o) { 51 if (new RegExp("(" + k + ")").test(fmt)) { 52 fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) 53 : (("00" + o[k]).substr(("" + o[k]).length))); 54 } 55 } 56 return fmt; 57 }; 58 ... 59 };
页面加载成功后,会加载JS将id为date1的输入框datetimepicker初始化,当你单击输入框时,向下弹出时间选择框。
Chapter Three . Mine Design
首先建立一个公共类并引入。
enDatetimepicker.js
$(function(e) { ... formatPrototype(); //JS原型初始化拓展 initDatetimepicker(); //初始化时间选择器 ... }); /** * JS原型初始化拓展 */ var formatPrototype = function() { ...//上面已经贴出 }; /** * 自定义元素初始化拓展,自适应屏幕高度并限制当前时间。IE click时间选择器页面跳动,完美即时自适应屏幕高度。 */ var initDatetimepicker = function() { // bootstap datetimepicker need $('.sapphire_date').addClass('date'); // mounse on in hand $('input', $('.sapphire_date')).css("cursor", "pointer"); // init datetimepicker by offset $(".sapphire_date").click(function() { var allHeight = $(document).height(); offset01 = $(this).offset(); offsettop01 = offset01.top; offsetbottom01 = allHeight - offsettop01; if (offsetbottom01 <= 500) { $(this).datetimepicker({ language : 'zh-CN', format : "yyyy-mm-dd hh:ii", todayBtn : 1, autoclose : 1, todayHighlight : 1, forceParse : 0, startDate : (new Date()).formate("yyyy-MM-dd HH:mm"), pickerPosition : 'top-right' }).on("hide", function() { $(this).datetimepicker('remove'); }); } else { $(this).datetimepicker({ language : 'zh-CN', format : "yyyy-mm-dd hh:ii", todayBtn : 1, autoclose : 1, todayHighlight : 1, forceParse : 0, startDate : (new Date()).formate("yyyy-MM-dd HH:mm"), pickerPosition : 'bottom-right' }).on("hide", function() { $(this).datetimepicker('remove'); }); } $(this).datetimepicker('show'); }); };
大功告成~!@当你加载该js时,并且声明该输入框class="... sapphire_date ..."就可以实现上述目标了。
让我感受下它强大的气场。
当输入框出现在当前页面下部的时候。
当输入框出现在当前页面上部的时候。
而且当鼠标悬停时,选择手势变成一只小手。呵呵哒。
Chapter Four. End
压压惊,这下我可以心安理得的关闭这几个BUG了吧!
如果你有更好的解决方式请指教我^_^。