基于datepicker的只选择年⽉的⽇期选择器
⼿头上的项⽬在开始做的时候,有那种需要⽤到⽇期选择的需求,本着快的原则,当时选择了datepicker这⼀款jqueryUI的插件,当然这个插件的质量相当不错,当时的需求是要完成⼀个有起⽌时间的选择,⾃⼰的实现也是通过改变datepicker的配置项来更新相应的限制,算起来,这都是⾃⼰刚⼯作的时候开发的东西,那时候⾃⼰的⽔平⼤概停留⼀下百度⼀下什么插件⽐较合适,做⼀个简单的封装之类的。
这两天还是这个⽇期选择,有⼀个新的需求,不要天的选择了,只要年、⽉。OMG,这是个什么⿁,但是没办法啊,产品说要做,关键⾃⼰也认同这个逻辑,那就做呗。本着最省劲的原则,那就还是拿datepicker,来做⼀个简单的改造,事实证明,我还是too young。
⾸先百度了⼀下,只显⽰年⽉的思路,⼤体的关键是,
1.设置dateForamt为:"yy-mm",//只显⽰年⽉
2.设置changeYear、changeMonth为true,//开启年、⽉对应的下拉框,⽤户选择起来更⽅便
3.设置onChangeMonthYear的回调函数,//年⽉发⽣改变之后,就可以获取当前选中的值,拿到这个值之后,设置输⼊框的值
4.页⾯上加⼀个style,将选择天的pane隐藏掉。
关键点⾮常的简单,但是⾥⾯的坑很⼤,慢慢跳。
当时只是⼤概试了⼀下,拿了⼀个输⼊框做了实验,觉得好像没问题,我就想之前已经有⼀个dateSelect的组件了,但是写的不太通⽤,基本上已经把很多东西都限定死了,那这⼀次,趁着这次实现的机会,重写⼀个通⽤性更⾼的组件,说⼲就⼲。
这种起⽌⽇期的组件的关键可能就是前后的限定了,开始的⽇期选定了之后,结束的⽇期的最⼩值不能⼩于开始时间的值,反过来,如果⼀上来结束的⽇期选定了之后,那么开始的⽇期就不能超过这个值。这个其实实现起来⽐较简单,⼤概就是每⼀个输⼊框绑定onSelect的回调,⼀旦选择了之后,把另⼀项的maxDate 或者minDate的值设定成这个值就可以了。来看⼀下代码:
/**
* date_selectCom_view.js
* 通⽤的⽇期选择组件,可⾃定义定制,⽤于组合(⼀开始、⼀结束)com-common
* ⽤法
var chooseType = 0;//先选中的类型 1-start 2-end
var dateSelect = $().dateSelectCom({
start:{
ele:$("#start"),
options:{
dateFormat:"yy-mm-dd",
maxDate: new Date(),
onSelect: function(value){
if(chooseType != 2){
dateSelect.setLimit(2, value);
chooseType = 1;
}
}
}
},
end:{
ele:$("#end"),
options:{
dateFormat:"yy-mm-dd",
maxDate: new Date(),
onSelect: function(value){
if(chooseType != 1){
dateSelect.setLimit(1, null, value);
chooseType = 2;
}
}
}
}
});
--重置
chooseType = 0;//这个也需要重置,要不然,会出问题
*/
(function(){
/**
* @param params{
start:{
options: ,
ele:
}, //开始的元素
end:{
options: ,
ele:
} //结束的元素
}
*/
var DateSelectCom = function(params){
if(params && params.start.ele && d.ele){
var options = {dateFormat: 'yy-mm-dd'};
this.startEle = $(params.start.ele);
this.startOptions = params.start.options;
this.init();//初始化
}
};
/**
* ⽇期的处理,低版本的ie对Date对象的兼容较差
*/
DateSelectCom.prototype.dateHandle = function(d){
if(d){
place){
var t;
if(d.indexOf("-") >= 0 && d.split("-").length == 2){//-分割,并且只有年⽉,补上最后⼀位,兼容IE                    d += "-1";
}
else if(d.indexOf("/") >= 0 && d.split("/").length ==2){// /分割
d += "/1";
}
t = d.replace(/-/g,'/');
return new Date(t);
}
return new Date(d);
}
return '';
};
/**
* 设置限制
* @param type 1-start 2-end
* @param min 最⼩值
* @param max 最⼤值
*/
DateSelectCom.prototype.setLimit = function(type, min, max){
if(type){
var minDate, maxDate, eleList = ["start", "end"],
ele = this[eleList[type-1]+"Ele"],
options = this[eleList[type-1]+"Options"];
if(min){
minDate = this.dateHandle(min);
ele.datepicker("option", "minDate", minDate);
}
else if(max){
if(!options.maxDate || (this.dateHandle(max)) < (this.dateHandle(options.maxDate))){
maxDate = this.dateHandle(max);
maxDate = this.dateHandle(max);
ele.datepicker("option", "maxDate", maxDate);
}
}
}
};
/**
* 设置值
* @param type 1-start 2-end
* @param value 值
*/
DateSelectCom.prototype.setValue = function(type, value){
var eleList = ["start", "end"],
ele = this[eleList[type-1]+"Ele"];
if(ele){
ele.datepicker("setDate", this.dateHandle(value));
}
};
/**
* 获取值
* @param type 1-start 2-end
*/
Value = function(type){
var eleList = ["start", "end"],
ele = this[eleList[type-1]+"Ele"];
if(ele){
return ele.val();
}
};
/**
* 设置默认值
* @param type 1-start 2-end
* @param val 默认值
*/
DateSelectCom.prototype.setDefault = function(type, val){
var eleList = ["start", "end"],
ele = this[eleList[type-1]+"Ele"];
if(ele){
ele.datepicker("option", "defaultDate", this.dateHandle(val));        }
};
/**
* 开始的初始化
*/
DateSelectCom.prototype.startInit = function(){
this.startEle.datepicker("destroy");
this.startEle.datepicker(this.startOptions);
};
/**
* 结束的初始化
*/
dInit = function(){
};
/**
* 重置
*/
set = function(){
this.startEle.val("");//清掉数据
this.startEle.val("");//清掉数据
this.startInit();
};
/**
* 初始化
*/
DateSelectCom.prototype.init = function(){
this.startInit();jquery是什么功能组件
};
$.fn.extend({dateSelectCom:function(params){
return new DateSelectCom(params);
}});
})();
因为是⼀个通⽤化的组件,所以只是封装了⼀个设置限定的函数,另外onSelect的绑定也没有集成在组件⾥⾯,⽽是通过初始化的时候传参的形式传进去,我觉得这样的⾃由度会更⾼⼀点。另外,这是我最后完成的版本,所以⾥⾯有⼀些之前没有提到的⼯具函数,这个会在后⾯提到,⼤家可以先忽略。
好啦,⾼潮来了,组件完成了之后,测试了⼀下,类似于住市⾥⾯⽤法的那段代码,就是正常的年⽉⽇的选择,ok,正常⼯作,完全可以拿来替代之前写的那个组件,那这次要实现的只显⽰年⽉的功能呢,把dateFormat设置为“yy-mm”,好像也没有什么特别的问题,哎,等⼀下,好像不对。我打开⽇期选择框,切换了年⽉之后,输⼊框的值变掉了。为什么我再次打开这个⽇期选择器的时候,输⼊框的值是对的,可是下⾯的⽇期是今天的⽇期?
我再说的具体⼀点,我打开⽇期选择器,选择2015-01,输⼊框变成2015-01,选择器关闭。再次打开
⽇期选择器,输⼊框还是2015-01,但是⽇期选择器显⽰选定的时间是2015-09(当前的⽇期),这很明显是不对的,是不是我在onChangeMonthYear的回调函数⾥⾯设置输⼊框的值的⽅法不对呢,只是设定了value,但是没有触发datepicker内部的更新。这个是有可能的,于是在value的设置之后,我增加了⼀些事件(change、blur、keyup)的触发,但是没什么⽤。查看了datepicker的源码之后,发现了setDate的接⼝⽅法,于是把设定value的这部分逻辑,换成了调⽤setDate接⼝,就是调⽤上边我封装的组件中的setValue的⽅法,换成了这个之后发现还是不对,那就只能从datepicker的源码上边去原因了。
1.setDate到底有没有成功
setDate调⽤的是内部的_setDateDatepicker⽅法。这个函数的内部实现如下,
/* Set the dates for a jQuery selection.
* @param  target element - the target input field or division or span
* @param  date Date - the new date
*/
_setDateDatepicker: function(target, date) {
var inst = this._getInst(target);
if (inst) {
this._setDate(inst, date);
this._updateDatepicker(inst);
this._updateAlternate(inst);
}
},
这⾥⾯的inst是datepicker内部维护的数据模型,当前选中的⽇期以及⽇期的格式等等信息都会存放在⾥⾯。从函数名上我们可以看到⾥⾯的逻辑⼤概是,更新数据、更新组件(渲染)以及更新属性。我在这个函数的最console出来了inst的值,(因为inst指向的是⼀个数据对象,所以它是动态的,可以在最后获取最新的值),发现我们设定的⽇期已经成功更新到数据模型上了,因此我们可以认定setDate是成功执⾏了,符合我们的期待。
2.第⼆次显⽰⽇期选择器的时候,原来的数据为什么失效了。
这⾥调⽤的是,datepicker的_showDatepicker函数,还是先放⼀下函数内部的实现,函数⾥⾯的console为调试使⽤,
/* Pop-up the date picker for a given input field.
* If false returned from beforeShow event handler do not show.
* @param  input  element - the input field attached to the date picker or
*    event - if triggered by focus
*/
*/
_showDatepicker: function(input) {
input = input.target || input;
console.log("", input, input.value);
if (LowerCase() !== "input") { // find from button/image trigger
input = $("input", input.parentNode)[0];
}
if ($.datepicker._isDisabledDatepicker(input) || $.datepicker._lastInput === input) { // already here    return;
}
var inst, beforeShow, beforeShowSettings, isFixed,
offset, showAnim, duration;
inst = $.datepicker._getInst(input);
console.log(2, inst, inst.input, inst.input.val());
console.log(3, inst.currentDay, inst.currentMonth, inst.currentYear);
console.log(4, inst.selectDay, inst.selectMonth, inst.selectYear);
if ($.datepicker._curInst && $.datepicker._curInst !== inst) {
$.datepicker._curInst.dpDiv.stop(true, true);
if ( inst && $.datepicker._datepickerShowing ) {
$.datepicker._hideDatepicker( $.datepicker._curInst.input[0] );
}
}
beforeShow = $.datepicker._get(inst, "beforeShow");
beforeShowSettings = beforeShow ? beforeShow.apply(input, [input, inst]) : {};
if(beforeShowSettings === false){
return;
}
datepicker_extendRemove(inst.settings, beforeShowSettings);
console.log(8, inst, inst.input, inst.input.val());
console.log(9, inst.currentDay, inst.currentMonth, inst.currentYear);
console.log(10, inst.selectDay, inst.selectMonth, inst.selectYear);
inst.lastVal = null;
$.datepicker._lastInput = input;
$.datepicker._setDateFromField(inst);
console.log(11, inst, inst.input, inst.input.val());
console.log(12, inst.currentDay, inst.currentMonth, inst.currentYear);
console.log(13, inst.selectDay, inst.selectMonth, inst.selectYear);
if ($.datepicker._inDialog) { // hide cursor
input.value = "";
}
if (!$.datepicker._pos) { // position below input
$.datepicker._pos = $.datepicker._findPos(input);
$.datepicker._pos[1] += input.offsetHeight; // add the height
}
isFixed = false;
$(input).parents().each(function() {
isFixed |= $(this).css("position") === "fixed";
return !isFixed;
});
offset = {left: $.datepicker._pos[0], top: $.datepicker._pos[1]};
$.datepicker._pos = null;
//to avoid flashes on Firefox
pty();
// determine sizing offscreen
inst.dpDiv.css({position: "absolute", display: "block", top: "-1000px"});
console.log(5, inst);

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。