一个被全世界错误使用的表单控件--日历控件

末鹿安然 提交于 2020-02-28 11:59:30

日历就是日历,但它不是合适的时间选择器。

大部分的表单中凡是涉及时间选择的,都会采用日历选择器。大部分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上面订阅事件,看官如果有办法,不要吝啬告诉我一声。
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!