input输入日期时间,自动格式化组件/工具
 
组件/工具使用说明
 
- 只能输入日期时间,不能选择
- 日期时间格式 yyyy-MM-dd HH:mm:ss
- 基于VUE框架
- 输入效果见下图
  
组件/工具解决的痛点
 
- 组件库日期时间组件,选日期时间很花时间 
  - 例如想快速得到 2021-12-14 20:10:22,需要先选日期,然后再选时间
 
- 可以快速输入目标日期和时间,不用关注日期和时间分隔符 - : 空格
组件/工具需要实现的功能
 
- 只允许输入数字
- 限制输入日期范围
- 按键删除时自动补入合法数字
- 输入数字自动删除后一位数字
- 输入和删除时光标位置移动
- 检测复制粘贴到输入框的内容
- 输入完成时,按回车键自动失焦
- 处理输入的不符合规则的日期
功能代码实现
 
 
<input 
    v-model="inOutTime"
    @focus="onFocus"
    @blur="onBlur"
    @input="inputDateTime($event)"
    @keydown="onKeydown"
    ref="inputDate"
    class="inputDate"
    :class="[`xxxx-${size}`]" />
<style scoped>
.inputDate {
  width: 100%;
  height: 40px;
  line-height: 40px;
  padding-left: 10px;
  border: none;
  outline: none;
  border-radius: 4px;
  border: 1px solid #dcdfe6;
}
.inputDate:focus {
  border-color: #409eff;
}
.xxxx-default {
  height: 40px;
  line-height: 40px;
}
.xxxx-medium {
  height: 36px;
  line-height: 36px;
}
.xxxx-small {
  height: 32px;
  line-height: 32px;
}
.xxxx-mini {
  height: 28px;
  line-height: 28px;
}
</style>
 
 
    function inputDateTime(ev) {
      
      let selectionStart = this.$refs.inputDate.selectionStart;
      let selectionEnd = this.$refs.inputDate.selectionEnd;
      
      console.log(ev.target.value);
    }
  
 
 
function dateToStr(datetime) {
  if (!datetime) {
    return '';
  }
  let year = datetime.getFullYear();
  let month = datetime.getMonth() + 1;
  let date = datetime.getDate();
  let hour = datetime.getHours();
  let minutes = datetime.getMinutes();
  let second = datetime.getSeconds();
  if (month < 10) {
    month = "0" + month;
  }
  if (date < 10) {
    date = "0" + date;
  }
  if (hour < 10) {
    hour = "0" + hour;
  }
  if (minutes < 10) {
    minutes = "0" + minutes;
  }
  if (second < 10) {
    second = "0" + second;
  }
  let time = year + "-" + month + "-" + date + " " + hour + ":" + minutes + ":" + second;
  return time;
}
const del = {
  4: '-',
  7: '-',
  10: ' ',
  13: ':',
  16: ':'
}
export function formatStringDate(str, selectionStart) {
  
  if (!/^[0-9-:\s]{18,20}$/.test(str) || str.length < 18) {
    return {newDate: dateToStr(new Date()), startB: 19};
  }
  
  let numStr = str.replace(/-|:|s|\s/g, '');
  if (numStr.length < 13) {
    return {newDate: dateToStr(new Date()), startB: 19};
  }
  
  const num = /^[0-9]$/;
  
  let startB = selectionStart;
  selectionStart = selectionStart - 1;
  let arrDate = str.split('');
  
  if (arrDate.length < 19) {
    if (del[startB]) {
      
      arrDate.splice(startB, 0, del[startB])
    } else {
      
      
      let obj = {
        0: '2',
        1: '0',
        5: '0'
      }
      arrDate.splice(startB, 0, obj[startB] || '1')
    }
    str = arrDate.join('');
  } else {
    
    
    const str2 = str.slice(selectionStart, selectionStart + 1);
    if (!num.test(str2)) {
      
      arrDate.splice(selectionStart, 1);
      return {newDate: arrDate.join(''), startB};
    }
    
    const str3 = str.slice(selectionStart + 1, selectionStart + 2);
    const reg1 = /^(-|:|s|\s)$/;
    if (reg1.test(str3)) {
      
      arrDate.splice(selectionStart + 2, 1);
      
      startB++;
    }
    
    if (num.test(str3)) {
      arrDate.splice(selectionStart + 1, 1);
    }
  }
  
  let str1 = arrDate.join('').replace(/-|:|s|\s/g, '');
  
  const regDate = /^20([0-9][0-9])-(0[1-9]|1[0-2])-([0-2][0-9]|3[01])$/;
  const regTime = /^(0[0-9]|1[0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9]/;
  
  let ymd = '';
  if (str1.length >= 8) {
    ymd = (str1).match(/(\d{4})(\d{2})(\d{2})/).filter((item, index) => index > 0).join('-');
  }
  if (!regDate.test(ymd)) {
    
    const reArr = str.split('');
    reArr.splice(selectionStart, 1);
    return {newDate: reArr.join(''), startB};
  }
  
  let hmsStr = (str1).slice(8), hms;
  if (hmsStr.length >= 6) {
    hms = hmsStr.match(/(\d{2})(\d{2})(\d{2})/).filter((item, index) => index > 0).join(':');
  }
  if (!regTime.test(hms)) {
    
    const reArr = str.split('');
    reArr.splice(selectionStart, 1);
    return {newDate: reArr.join(''), startB};
  }
  return {newDate: `${ymd} ${hms}`, startB};
}
 
 
function strDateTime(str) {
  var reg = /^(\d{4})(-|\/)(\d{2})\2(\d{2}) (\d{2}):(\d{2}):(\d{2})$/;
  var r = str.match(reg);
  if (r == null) return false;
  var d = new Date(r[1], r[3] - 1, r[4], r[5], r[6], r[7]);
  return (d.getFullYear() === Number(r[1]) && (d.getMonth() + 1) === Number(r[3]) && d.getDate() === Number(r[4]) && d.getHours() === Number(r[5]) && d.getMinutes() === Number(r[6]) && d.getSeconds() === Number(r[7]));
}
 
 
this.$refs.inputDate.setSelectionRange(selectionStart, selectionStart);
 
 
<template>
  <div>
    <input 
          v-model="inOutTime"
          @focus="onFocus"
          @blur="onBlur"
          @input="inputDateTime($event)"
          @keydown="onKeydown"
          ref="inputDate"
          class="inputDate"
          :class="[`xxxx-${size}`]" />
  </div>
</template>
<script>
import { formatStringDate } from "utils";
import { dateToStr } from "public";
export default {
  props: {
    initTime: {
      type: String,
      required: true,
      default: dateToStr(new Date())
    },
    size: {
      type: String,
      default: 'small'
    }
  },
  data() {
    return {
      inOutTime: this.initTime
    }
  },
  methods: {
    inputDateTime(ev) {
      let selectionStart = this.$refs.inputDate.selectionStart;
      const options = formatStringDate(ev.target.value, selectionStart);
      this.inOutTime = options.newDate;
      if (options.startB !== selectionStart) {
        selectionStart = options.startB;
      }
      this.$nextTick(() => {
        this.$refs.inputDate.setSelectionRange(selectionStart, selectionStart);
      })
    },
    onFocus() {
    },
    onBlur() {
      if (!this.strDateTime(this.inOutTime)) {
        this.inOutTime = dateToStr(new Date());
      }
    },
    onKeydown(e) {
      let keyCode = window.event ? e.keyCode : e.which;
      
      if (keyCode === 13) {
        this.$refs.inputDate.blur();
        if (!this.strDateTime(this.inOutTime)) {
          this.inOutTime = dateToStr(new Date());
        }
        this.$emit('getTime', this.inOutTime);
      }
    },
    strDateTime(str) {
			var reg = /^(\d{4})(-|\/)(\d{2})\2(\d{2}) (\d{2}):(\d{2}):(\d{2})$/;
      var r = str.match(reg);
			if (r == null) return false;
			var d = new Date(r[1], r[3] - 1, r[4], r[5], r[6], r[7]);
			return (d.getFullYear() === Number(r[1]) && (d.getMonth() + 1) === Number(r[3]) && d.getDate() === Number(r[4]) && d.getHours() === Number(r[5]) && d.getMinutes() === Number(r[6]) && d.getSeconds() === Number(r[7]));
		}
  }
}
</script>
 
补充说明
 
- 若需要实时获取处理之后的日期时间,可以在组件上使用v-model,具体代码请参考vue文档
- 组件基于VUE编写,核心方法formatStringDate不依赖框架,原生JS、react均可使用