首页 > 试题

monthyear

更新时间:2022-11-14 13:43:30 阅读: 评论:0

中考前沿2020答案数学-烧的组词


2022年11月14日发(作者: 春 )

基于datepicker的只选择年⽉的⽇期选择器

⼿头上的项⽬在开始做的时候,有那种需要⽤到⽇期选择的需求,本着快的原则,当时选择了datepicker这⼀款jqueryUI的插件,当然这个插件的质量相当不

错,当时的需求是要完成⼀个有起⽌时间的选择,⾃⼰的实现也是通过改变datepicker的配置项来更新相应的限制,算起来,这都是⾃⼰刚⼯作的时候开发的东

西,那时候⾃⼰的⽔平⼤概停留⼀下百度⼀下什么插件⽐较合适,做⼀个简单的封装之类的。

这两天还是这个⽇期选择,有⼀个新的需求,不要天的选择了,只要年、⽉。OMG,这是个什么⿁,但是没办法啊,产品说要做,关键⾃⼰也认同这个逻辑,

那就做呗。本着最省劲的原则,那就还是拿datepicker,来做⼀个简单的改造,事实证明,我还是tooyoung。

⾸先百度了⼀下,只显⽰年⽉的思路,⼤体的关键是,

1.设置dateForamt为:"yy-mm",//只显⽰年⽉

2.设置changeYear、changeMonth为true,//开启年、⽉对应的下拉框,⽤户选择起来更⽅便

3.设置onChangeMonthYear的回调函数,//年⽉发⽣改变之后,就可以获取当前选中的值,拿到这个值之后,设置输⼊框的值

4.页⾯上加⼀个style,将选择天的pane隐藏掉。

关键点⾮常的简单,但是⾥⾯的坑很⼤,慢慢跳。

当时只是⼤概试了⼀下,拿了⼀个输⼊框做了实验,觉得好像没问题,我就想之前已经有⼀个dateSelect的组件了,但是写的不太通⽤,基本上已经把很多东西

都限定死了,那这⼀次,趁着这次实现的机会,重写⼀个通⽤性更⾼的组件,说⼲就⼲。

这种起⽌⽇期的组件的关键可能就是前后的限定了,开始的⽇期选定了之后,结束的⽇期的最⼩值不能⼩于开始时间的值,反过来,如果⼀上来结束的⽇期选定

了之后,那么开始的⽇期就不能超过这个值。这个其实实现起来⽐较简单,⼤概就是每⼀个输⼊框绑定onSelect的回调,⼀旦选择了之后,把另⼀项的maxDate

或者minDate的值设定成这个值就可以了。来看⼀下代码:

/**

*date_lectCom_

*通⽤的⽇期选择组件,可⾃定义定制,⽤于组合(⼀开始、⼀结束)com-common

*⽤法

varchooType=0;//先选中的类型1-start2-end

vardateSelect=$().dateSelectCom({

start:{

ele:$("#start"),

options:{

dateFormat:"yy-mm-dd",

maxDate:newDate(),

onSelect:function(value){

if(chooType!=2){

it(2,value);

chooType=1;

}

}

}

},

end:{

ele:$("#end"),

options:{

dateFormat:"yy-mm-dd",

maxDate:newDate(),

onSelect:function(value){

if(chooType!=1){

it(1,null,value);

chooType=2;

}

}

}

}

});

--重置

();

();

chooType=0;//这个也需要重置,要不然,会出问题

*/

(function(){

/**

*@paramparams{

start:{

options:,

ele:

},//开始的元素

end:{

options:,

ele:

}//结束的元素

}

*/

varDateSelectCom=function(params){

if(params&&&&){

varoptions={dateFormat:'yy-mm-dd'};

le=$();

ptions=s;

=$();

ions=s;

();//初始化

}

};

/**

*⽇期的处理,低版本的ie对Date对象的兼容较差

*/

ndle=function(d){

if(d){

if(e){

vart;

if(f("-")>=0&&("-").length==2){//-分割,并且只有年⽉,补上最后⼀位,兼容IE

d+="-1";

}

elif(f("/")>=0&&("/").length==2){///分割

d+="/1";

}

t=e(/-/g,'/');

returnnewDate(t);

}

returnnewDate(d);

}

return'';

};

/**

*设置限制

*@paramtype1-start2-end

*@parammin最⼩值

*@parammax最⼤值

*/

it=function(type,min,max){

if(type){

varminDate,maxDate,eleList=["start","end"],

ele=this[eleList[type-1]+"Ele"],

options=this[eleList[type-1]+"Options"];

if(min){

minDate=ndle(min);

cker("option","minDate",minDate);

}

elif(max){

if(!e||(ndle(max))<(ndle(e))){

maxDate=ndle(max);

maxDate=ndle(max);

cker("option","maxDate",maxDate);

}

}

}

};

/**

*设置值

*@paramtype1-start2-end

*@paramvalue值

*/

ue=function(type,value){

vareleList=["start","end"],

ele=this[eleList[type-1]+"Ele"];

if(ele){

cker("tDate",ndle(value));

}

};

/**

*获取值

*@paramtype1-start2-end

*/

ue=function(type){

vareleList=["start","end"],

ele=this[eleList[type-1]+"Ele"];

if(ele){

();

}

};

/**

*设置默认值

*@paramtype1-start2-end

*@paramval默认值

*/

ault=function(type,val){

vareleList=["start","end"],

ele=this[eleList[type-1]+"Ele"];

if(ele){

cker("option","defaultDate",ndle(val));

}

};

/**

*开始的初始化

*/

nit=function(){

cker("destroy");

cker(ptions);

};

/**

*结束的初始化

*/

t=function(){

cker("destroy");

cker(ions);

};

/**

*重置

*/

=function(){

("");//清掉数据

("");//清掉数据

("");

nit();

t();

};

/**

*初始化

*/

=function(){

nit();

t();

};

$.({dateSelectCom:function(params){

returnnewDateSelectCom(params);

}});

})();

因为是⼀个通⽤化的组件,所以只是封装了⼀个设置限定的函数,另外onSelect的绑定也没有集成在组件⾥⾯,⽽是通过初始化的时候传参的形式传进去,我觉

得这样的⾃由度会更⾼⼀点。另外,这是我最后完成的版本,所以⾥⾯有⼀些之前没有提到的⼯具函数,这个会在后⾯提到,⼤家可以先忽略。

好啦,⾼潮来了,组件完成了之后,测试了⼀下,类似于住市⾥⾯⽤法的那段代码,就是正常的年⽉⽇的选择,ok,正常⼯作,完全可以拿来替代之前写的那

个组件,那这次要实现的只显⽰年⽉的功能呢,把dateFormat设置为“yy-mm”,好像也没有什么特别的问题,哎,等⼀下,好像不对。我打开⽇期选择框,切

换了年⽉之后,输⼊框的值变掉了。为什么我再次打开这个⽇期选择器的时候,输⼊框的值是对的,可是下⾯的⽇期是今天的⽇期?

我再说的具体⼀点,我打开⽇期选择器,选择2015-01,输⼊框变成2015-01,选择器关闭。再次打开⽇期选择器,输⼊框还是2015-01,但是⽇期选择器显⽰

选定的时间是2015-09(当前的⽇期),这很明显是不对的,是不是我在onChangeMonthYear的回调函数⾥⾯设置输⼊框的值的⽅法不对呢,只是设定了

value,但是没有触发datepicker内部的更新。这个是有可能的,于是在value的设置之后,我增加了⼀些事件(change、blur、keyup)的触发,但是没什么

⽤。查看了datepicker的源码之后,发现了tDate的接⼝⽅法,于是把设定value的这部分逻辑,换成了调⽤tDate接⼝,就是调⽤上边我封装的组件中的

tValue的⽅法,换成了这个之后发现还是不对,那就只能从datepicker的源码上边去找原因了。

e到底有没有成功

tDate调⽤的是内部的_tDateDatepicker⽅法。这个函数的内部实现如下,

/*SetthedatesforajQuerylection.

*@paramtargetelement-thetargetinputfieldordivisionorspan

*@paramdateDate-thenewdate

*/

_tDateDatepicker:function(target,date){

varinst=this._getInst(target);

if(inst){

this._tDate(inst,date);

this._updateDatepicker(inst);

this._updateAlternate(inst);

}

},

这⾥⾯的inst是datepicker内部维护的数据模型,当前选中的⽇期以及⽇期的格式等等信息都会存放在⾥⾯。从函数名上我们可以看到⾥⾯的逻辑⼤概是,更新

数据、更新组件(渲染)以及更新属性。我在这个函数的最console出来了inst的值,(因为inst指向的是⼀个数据对象,所以它是动态的,可以在最后获取最新

的值),发现我们设定的⽇期已经成功更新到数据模型上了,因此我们可以认定tDate是成功执⾏了,符合我们的期待。

2.第⼆次显⽰⽇期选择器的时候,原来的数据为什么失效了。

这⾥调⽤的是,datepicker的_showDatepicker函数,还是先放⼀下函数内部的实现,函数⾥⾯的console为调试使⽤,

/*Pop-upthedatepickerforagiveninputfield.

*IffalreturnedfrombeforeShoweventhandlerdonotshow.

*@paraminputelement-theinputfieldattachedtothedatepickeror

*event-iftriggeredbyfocus

*/

*/

_showDatepicker:function(input){

input=||input;

("",input,);

if(rCa()!=="input"){//findfrombutton/imagetrigger

input=$("input",Node)[0];

}

if($.datepicker._isDisabledDatepicker(input)||$.datepicker._lastInput===input){//alreadyhere

return;

}

varinst,beforeShow,beforeShowSettings,isFixed,

offt,showAnim,duration;

inst=$.datepicker._getInst(input);

(2,inst,,());

(3,tDay,tMonth,tYear);

(4,Day,Month,Year);

if($.datepicker._curInst&&$.datepicker._curInst!==inst){

$.datepicker._(true,true);

if(inst&&$.datepicker._datepickerShowing){

$.datepicker._hideDatepicker($.datepicker._[0]);

}

}

beforeShow=$.datepicker._get(inst,"beforeShow");

beforeShowSettings=beforeShow?(input,[input,inst]):{};

if(beforeShowSettings===fal){

return;

}

datepicker_extendRemove(gs,beforeShowSettings);

(8,inst,,());

(9,tDay,tMonth,tYear);

(10,Day,Month,Year);

l=null;

$.datepicker._lastInput=input;

$.datepicker._tDateFromField(inst);

(11,inst,,());

(12,tDay,tMonth,tYear);

(13,Day,Month,Year);

if($.datepicker._inDialog){//hidecursor

="";

}

if(!$.datepicker._pos){//positionbelowinput

$.datepicker._pos=$.datepicker._findPos(input);

$.datepicker._pos[1]+=Height;//addtheheight

}

isFixed=fal;

$(input).parents().each(function(){

isFixed|=$(this).css("position")==="fixed";

return!isFixed;

});

offt={left:$.datepicker._pos[0],top:$.datepicker._pos[1]};

$.datepicker._pos=null;

//toavoidflashesonFirefox

();

//determinesizingoffscreen

({position:"absolute",display:"block",top:"-1000px"});

(5,inst);

(5,inst);

(6,tDay,tMonth,tYear);

(7,Day,Month,Year);

$.datepicker._updateDatepicker(inst);

//fixwidthfordynamicnumberofdatepickers

//andadjustpositionbeforeshowing

offt=$.datepicker._checkOfft(inst,offt,isFixed);

({position:($.datepicker._inDialog&&$.blockUI?

"static":(isFixed?"fixed":"absolute")),display:"none",

left:+"px",top:+"px"});

if(!){

showAnim=$.datepicker._get(inst,"showAnim");

duration=$.datepicker._get(inst,"duration");

("z-index",datepicker_getZindex($(input))+1);

$.datepicker._datepickerShowing=true;

if($.effects&&$.[showAnim]){

(showAnim,$.datepicker._get(inst,"showOptions"),duration);

}el{

[showAnim||"show"](showAnim?duration:null);

}

if($.datepicker._shouldFocusInput(inst)){

();

}

$.datepicker._curInst=inst;

}

},

后来发现,在我console的10、11之间inst的值发⽣了变化,10之前的inst的值为我们预期的值,11之后inst的值就变成了当前的⽇期。10、11直接唯⼀有嫌疑

的就是这⾏代码了。

$.datepicker._tDateFromField(inst);

我们来看⼀下这个函数的内部实现。

/*Parexistingdateandinitialidatepicker.*/

_tDateFromField:function(inst,noDefault){

if(()===l){

return;

}

(,());

vardateFormat=this._get(inst,"dateFormat"),

dates=l=?():null,

defaultDate=this._getDefaultDate(inst),

date=defaultDate,

ttings=this._getFormatConfig(inst);

(dateFormat,dates,ttings);

("~~~~~~~",defaultDate);

try{

date=ate(dateFormat,dates,ttings)||defaultDate;

(date,1);

}catch(event){

dates=(noDefault?"":dates);

(dates,2);

}

(date,dates);

edDay=e();

nth=edMonth=th();

ar=edYear=lYear();

tDay=(dates?e():0);

tMonth=(dates?th():0);

tYear=(dates?lYear():0);

(14,tDay,tMonth,tYear,edYear,edMonth);

this._adjustInstDate(inst);

(14-1,tDay,tMonth,tYear,edYear,edMonth);

},

这个函数结束之后,inst的值就变掉了,我们在函数的最后可以看到inst的赋值,⽽这个值的来源就是date这个变量,我们看⼀下try,catch那段逻辑,date来源

于parDate的返回值。如果没有返回,就是默认值,默认值如果我们不设定的话,就是当前的时间。真相估计就是因为这个了,为了确定最后的犯⼈,我们看

⼀下parDate的实现,代码很长,基本上是⼀个⽇期的解析,⽤的是传进去的dateFormat和date按照固定的规则解析出来。只看⼀下这个函数的最后⼏⾏。

date=this._daylightSavingAdjust(newDate(year,month-1,day));

if(lYear()!==year||th()+1!==month||e()!==day){

throw"Invaliddate";//E.g.31/02/00

}

returndate;

这⾥⾯year,month,day是根据传进去的值解析出来的时间,我们再回到前⾯,传进这个解析函数的值是什么,

dates=l=?():null,

是当前输⼊框的value,对于之前我举的例⼦的话,就是2015-04,在解析函数⾥⾯解析出来的year是2015,month是4,day是-1,是的,你没看错day=-1,造

成这个结果的原因有两个,第⼀个day默认值给的是-1,第⼆个,传进去的dateFormat是“yy-mm”,所以day没有解析,直接是默认值。就是因为day=-1,所以

解析函数最后的那个判断就过不了,解析函数会直接抛出⼀个错误,inst的值就直接会变成默认值,⼀切都说通了。

那么,怎么去修正这个问题呢,我最开始的想法是,直接动源码,在⾥⾯加⼀个容错,解析函数⾥⾯我摘的代码之前,如果day=-1,直接变为1,做⼀个兼容,

试了⼀下没什么问题,但是datepicker毕竟是别⼈写的插件,我不知道我这样的感动会不会有别的影响,⽽且我们⽹站上已经有⼤量页⾯⽤到这个插件,万⼀改

坏了那就糟了,所以我没敢动,事实证明,幸亏我没动,这个坑⽐我想的深多了。

不动源码的情况下,怎么解决这个问题呢,⼀筹莫展的时候,我看到了这个,⾥⾯提到datepicker对这种只有年⽉的⽀持有点问题,事实上我觉得datepicker的

兼容已经写得很不错了,毕竟这种只有年⽉的情况⽐较少见,这种情况的兼容稍微差点,也可以理解,⾥⾯有⼈提出了⼀个解决的⽅案。

$('#asdf').datepicker({changeMonth:true,changeYear:true,dateFormat:'mm/yy',beforeShow:function(input,inst)

{//getter

vardefaultDate=$("#asdf").datepicker("option","defaultDate");

//tter

$("#asdf").datepicker("option","defaultDate",xact($("#asdf").val(),"M/yyyy"));

}});

这⾥⾯的关键就是设定beforeShow函数,这个函数会在⽇期选择器显⽰之前调⽤执⾏。再回到这个错误的原因上来,_tDateFromField函数内部更新了inst,

如果这个输⼊框的value解析不出来就更新成dafaultValue,那么我们可以在⽇期选择器打开之前,把value的值变成defaultDate,那么value即使解析失败,inst

的值,也是我们想要的值。思路就是这么个思路,可以说这就是这个问题的关键了。

本来,问题到这已经解决了⼤半了,但是在后⾯的调试中,发现涉及到datepicker更新option的时候可能都会触发onChangeMonthYear事件,也会导致⼀系列

的问题,⽽且我还发现除了⽇期解析的那个函数以外,_tDate对传⼊空date的情况,会把date转换成当前的时间,触发onChangeMonthYear,但是⼜会把对

应输⼊框的value清空,这就会导致开始的⽇期明明是空的,结束的⽇期却有最⼩值的限制,所以我为什么说这个坑很深。

上⼀下最后完成的代码

varchooType=0;//先选中的类型1-start2-end

vardateSelect=$().dateSelectCom({

start:{

ele:$("#starttime"),

options:{

dateFormat:'yy-mm',

changeMonth:true,

changeYear:true,

monthNamesShort:["⼀⽉","⼆⽉","三⽉","四⽉","五⽉","六⽉","七⽉","⼋⽉","九⽉","⼗⽉","⼗⼀⽉","⼗⼆⽉"],

maxDate:newDate(),

onChangeMonthYear:function(year,month){

varvalue=year+"-"+month;

varoldValue=ue(2);

ue(1,value);

if(chooType!=2){

chooType=1;

it(2,value);

ue(2,oldValue);

}

},

beforeShow:function(input,inst)

{

varvalue=ue(1);

varoldValue=ue(2);

if(value){

ault(1,value);

ue(1,value);

oldValue&&ue(2,oldValue);

}el{

oldValue&&ue(2,oldValue);//如果另⼀项有值,以另⼀项为准

ue(1,newDate());

}

}

}

},

end:{

ele:$("#endtime"),

options:{

dateFormat:'yy-mm',

changeMonth:true,

changeYear:true,

monthNamesShort:["⼀⽉","⼆⽉","三⽉","四⽉","五⽉","六⽉","七⽉","⼋⽉","九⽉","⼗⽉","⼗⼀⽉","⼗⼆⽉"],

maxDate:newDate(),

onChangeMonthYear:function(year,month){

varvalue=year+"-"+month;

varoldValue=ue(1);

varoldValue=ue(1);

ue(2,value);

if(chooType!=1){

chooType=2;

it(1,null,value);

ue(1,oldValue);

}

},

beforeShow:function(input,inst)

{

varvalue=ue(2);

varoldValue=ue(1);

if(value){

ault(2,value);

ue(2,value);

oldValue&&ue(1,oldValue);

}

el{

oldValue&&ue(1,oldValue);//如果另⼀项有值,以另⼀项为准

ue(2,newDate());

}

}

}

}

});

⾄此,折腾了两三天,总算把这个完成了,感想的话有以下⼏点:

cker写的真不错,通⽤化的程度⾮常⾼,考虑的情况很多。

2.⾃⼰调试代码的能⼒应该是有提升的,要放在以前,估计会是两眼⼀抹⿊的情况。

3.知道了原理去反推结果⾮常的⽅便,在做的过程中陆续发现了很多问题,因为原理通了,就很好改了。

4.⾃⼰在遇到那种⽐较深的逻辑的情况,依然是很艰难,内存不够,堆栈不够深,还需要继续努⼒啊。

本文发布于:2022-11-14 13:43:30,感谢您对本站的认可!

本文链接:http://www.wtabcd.cn/fanwen/fan/88/17758.html

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

下一篇:错别字的危害
标签:monthyear
相关文章
留言与评论(共有 0 条评论)
   
验证码:
推荐文章
排行榜
Copyright ©2019-2022 Comsenz Inc.Powered by © 专利检索| 网站地图