日历就是日历,但它不是合适的时间选择器。
大部分的表单中凡是涉及时间选择的,都会采用日历选择器。大部分UI框架也会默认提供。在许多场景中使用这种控件并不合适,特别是一些二流的公司甚至没有和日历同步时间。
比如:
看起来挺炫,其实毫无意义。这个控件不会和字段内的时间同步,照理说控件显示的时候应该反应字段内的日期和时间。如果我幸幸苦苦选择到指定日期,不小心点错了一格,我必须重新来一遍。
再有一个情况是,如果是输入生日,那么必须在年份上下按钮点100次(如果100岁的话)。
采用html内置的选择器是更加合理的时间选择器。
以下是我写的控件:
{fieldName: "publishdAt",inputLabel: '发表日期',years:"-10,+10",ftype:'datetime'/*date*/,required:true,validators:{},gridSize:"1-2"},
配置很好理解,years以当前时间(不一定后面再说)为参考,-10,+10,当然是显示前后10年(根据需要),如果是编辑,字段本身已经有了值,那么这个前后是根据这个值的年份前后10年。
这样设计还有问题,如果年份超越了这个范围,不是无法输入了吗?当你点击日期select的时候,最下方有一个“其它”选项,当你选择这个值时,select会变成text字段,允许你输入任何年份,当你输入年份,text失去焦点之后,select字段又会回来。
还有一个隐藏的功能,就是当你改变年月或者月份的时候,这个控件的view会重画,何必呢?因为月份不同,日期的范围会变化。
外观:
最后是源代码:
var Lang = Y.Lang,
Ob = Y.Object,
fieldsViewNs = Y.namespace("M3958.CusFieldView");
fieldsViewNs.CusDateTimeField = Y.Base.create('cusDateTimeField', Y.View, [], {
events: {
'input': {blur: 'onInputBlur'}
},
/**
* 控制input的宽度可以通过设置width style.
*/
selectTpl: Y.Template.Micro.compile(
'<select class="<%= this.dmodel.type %>" style="display:inline;margin-left:2px;">' +
'<% for (var i=this.dmodel.range[0]; i<=this.dmodel.range[1];i++) { %>' +
'<option value=<%= i %><%= (i == data.dmodel.cur) ? " selected" : "" %>><%= i + data.dmodel.postfix %></option>' +
'<% } %>' +
'</select>'
),
template: Y.Template.Micro.compile(
'<label for="<%= this.guid %>"><%= this.fieldDescription.inputLabel %></label>' +
'<input type="text" placeholder="年份" style="width:50px;display:none;">'+
'<select id="<%= this.guid %>" class="<%= this.dmodel.type %>" style="display:inline;">' +
'<% for (var i=this.dmodel.range[0]; i<=this.dmodel.range[1];i++) { %>' +
'<option value=<%= i %><%= (i == data.dmodel.cur) ? " selected" : "" %>><%= i + data.dmodel.postfix %></option>' +
'<% } %>' +
'<option value="otheryear">其它</option>' +
'</select>'
),
initializer: function (){
var container = this.get('container'),
self = this,
model = this.get('model'),
fieldDescription = this.get('fieldDescription');
model.after('clientValidateErrorChange',function(e){
var validateResult = e.newVal;
if (!validateResult) {
return;
}
if (validateResult.isForField(fieldDescription.fieldName)) {
if (validateResult.msg) {
container.addClass("validate-error");
} else {
container.removeClass("validate-error");
}
}
},this);
this.on('destroy',function(e){
container.all('select').detachAll();
});
},
render: function () {
var container = this.get('container'),
fieldDescription = this.get('fieldDescription'),
formStyle = this.get('formStyle'),
label = fieldDescription.inputLabel,
tnum = fieldDescription.ftype === 'datetime' ? 6 : 3,
helpInline = fieldDescription.helpInline,
self = this,
html,
yselect,
mselect,
dselect,
docfragment,
guid = Y.guid(),
dmodel,
idx = 1,
inputNode;
if (container.all('select')) {
container.all('select').detachAll();
}
if(Lang.isFunction(helpInline)){
helpInline = helpInline.call(this);
}
if(Lang.isFunction(label)){
label = label.call(this);
}
if(fieldDescription.required && (Lang.isBoolean(fieldDescription.required) || Lang.isString(fieldDescription.required))){
label = '<strong>' + label + '</strong>';
}
dmodel = this.createDmodel();
html = this.template({
guid: guid,
dmodel: dmodel[0],
fieldDescription: fieldDescription
}
);
container.setHTML(html);
docfragment = Y.one(Y.config.doc.createDocumentFragment());
for (;idx < tnum;idx++) {
docfragment.append(this.selectTpl({
dmodel: dmodel[idx]
}
));
}
container.append(docfragment);
if (formStyle === 'aligned') {
container.addClass('pure-control-group');
} else {
if (fieldDescription.gridSize) {
container.addClass('pure-u-' + fieldDescription.gridSize);
} else {
container.addClass('pure-u-1');
}
}
yselect = container.one('select.year');
mselect = container.one('select.month');
dselect = container.one('select.date');
yselect.after('change',function(){
self.afterSelectChange('y');
});
mselect.after('change',function(){
self.afterSelectChange('m');
});
dselect.after('change',function(){
self.afterSelectChange('d');
});
return this;
},
createDmodel: function(){
var container = this.get('container'),
fieldDescription = this.get('fieldDescription'),
years = fieldDescription.years,
model = this.get('model'),
value = model.get(fieldDescription.fieldName),
now = value ? new Date(value) : new Date(),
self = this,
yearstart,
yearend,
dmodel = [],
yearr = years.split(",");
if ((yearr[0].indexOf('-') === -1) && (yearr[0].indexOf('+') === -1)) { //没有加减号,值现在
yearstart = now.getFullYear();
} else {
yearstart = now.getFullYear() + parseInt(yearr[0]);
}
if ((yearr[1].indexOf('-') === -1) && (yearr[1].indexOf('+') === -1)) { //没有加减号,值现在
yearend = now.getFullYear();
} else {
yearend = now.getFullYear() + parseInt(yearr[1]);
}
dmodel.push({range:[yearstart,yearend],cur:now.getFullYear(),type:'year',postfix:'年'});
dmodel.push({range:[1,12],cur:now.getMonth() + 1,type:'month',postfix:'月'});
dmodel.push({range:[1,Y.M3958.Util.DateTime.monthEnd(now.getFullYear(),now.getMonth())],cur:now.getDate(),type:'date',postfix:'日'});
dmodel.push({range:[0,23],cur:now.getHours(),type:'hour',postfix:'时'});
dmodel.push({range:[0,59],cur:now.getMinutes(),type:'minute',postfix:'分'});
dmodel.push({range:[0,59],cur:now.getSeconds(),type:'second',postfix:'秒'});
return dmodel;
},
getInputValue : function(){
var container = this.get('container'),
input = container.one('select');
return input.get('value');
},
getDateTimeLong : function(){
return Y.M3958.UtilsClass.DateUtils.tolong(this.getInputValue());
},
_getValue : function(){
var container = this.get('container'),
inputs = container.all('select'),
value = [];
inputs.each(function(nd){
value.push(parseInt(nd.get('value'),10));
});
return value;
},
saveValue : function(){
var fieldDescription = this.get('fieldDescription'),
model = this.get('model'),
v = this._getValue(),
dtv = new Date();
Y.Array.each(v,function(one,idx){
if (idx === 0) {
dtv.setFullYear(one);
} else if (idx === 1) {
dtv.setMonth(one - 1);
} else if (idx === 2) {
dtv.setDate(one);
} else if (idx === 3) {
dtv.setHours(one);
} else if (idx === 4) {
dtv.setMinutes(one);
} else if (idx === 5) {
dtv.setSeconds(one);
}
});
if (model) {
model.set(fieldDescription.fieldName,dtv.getTime());
}
},
afterSelectChange: function(t){
var fieldDescription = this.get('fieldDescription'),
container = this.get('container'),
yselect = container.one('select.year'),
dinput = container.one('input'),
model = this.get('model');
if (t === 'y' && yselect.get('value') === 'otheryear') {
dinput.setStyle('display','inline');
yselect.setStyle('display','none');
dinput.focus();
return;
}
this.saveValue();
if (model && model.validateOneField) {
model.validateOneField(fieldDescription);
}
if (t === 'm' || t === 'y') {
this.render();
}
},
onInputBlur: function() {
var fieldDescription = this.get('fieldDescription'),
container = this.get('container'),
yselect = container.one('select.year'),
dvalue = container.one('input').get('value'),
model = this.get('model'),
value = model.get(fieldDescription.fieldName),
d = new Date(value);
/**
* 只是改变year的值,其它的不变。
*/
if (dvalue) {
d.setFullYear(parseInt(dvalue,10));
model.set(fieldDescription.fieldName,d.getTime());
this.render();
}
}
},{
ATTRS: {
container: {
valueFn: function () {
return Y.Node.create('<div></div>');
}
},
fieldDescription : {
value : null
},
model: {
value: null
}
}
});
这个select change事件不会冒泡(ie<10),所以必须拙劣的在每个select上面订阅事件,看官如果有办法,不要吝啬告诉我一声。
来源:oschina
链接:https://my.oschina.net/u/148211/blog/175754