基于elementui实现的日期组件,自动格式化日期

在平时的工作中,对于日期控件,甲方爸爸们都有各种各样的定制化要求。

这不,又来了一个定制需求:

要求日期控件没有值的时候默认显示0000-00-00,用户点击日期控件时,可以弹出框的方式选择,也可以手工输入,手工输入时,自动进行yyyy-MM-dd的格式化。

最终效果图如下:

image.png
image.png
image.png

呃。。。。。。

翻阅一下elementui官方文档,是的,elementui没有这个功能。

那就只能自己写了。

思路:
1、使用input框作为手工输入的情况,并且监听输入框的文字变化,自动进行日期格式化
2、对于弹出框的选择方式,提供一个按钮,用户点击该按钮时,将el-date-picker显示出来
3、自定义v-model指令,用于双向绑定。

不过,代码里用了比较多的setTimeout方法,可能不是最优方案,但尝试了很多其他办法都没能解决,所以现阶很多地方用了setTimeout,如果大家有什么好的方式,欢迎指导,感谢!

详细代码如下:

<template>
  <span class="my-picker">
    <!-- @input="handleInput" -->
    <el-input
      :disabled="disabled"
      size="mini"
      style="width: 140px"
      v-show="!showPicker"
      v-model="inputValue"
      @focus="handleFocus"
      @input="handleInput"
      @click.native="handleClick"
      @blur="handleBlur"
      :id="id"
    >
      <i
        slot="prefix"
        class="el-input__icon el-icon-date point"
        @click="handlePicker"
      >
      </i>
    </el-input>
    <el-date-picker
      :disabled="disabled"
      size="mini"
      style="width: 140px"
      v-show="showPicker"
      ref="datePicker"
      v-model="defaultValue"
      type="date"
      @blur="handleBlur"
      @change="handleInput"
      :clearable="false"
      value-format="yyyy-MM-dd"
      placeholder="选择日期"
    >
    </el-date-picker>
  </span>
</template>

<script>
import { getCursorPos, setCursorPos } from "@/util/util";
import { dateFormat10 } from "@/util/date";
export default {
  name: "MyDatepicker",
  model: {
    prop: "value",
    event: "input"
  },
  props: {
    width: {
      type: [String],
      default: "220px"
    },
    value: {
      type: [String],
      default: "0000-00-00" //dateFormat10(new Date())
    },
    disabled: {
      type: Boolean,
      default: false
    }
  },
  data() {
    return {
      defaultValue: "0000-00-00",
      id: "input" + Math.random(),
      showPicker: false,
      currentKeyCode: null, //当前键盘码值
      lastPos: -1 //光标上次所处的位置
    };
  },
  computed: {
    inputValue: {
      get() {
        return this.defaultValue;
      },
      set(val) {
        let begin = new Date().getTime();
        const that = this;
        const obj = document.getElementById(this.id);
        const pos = this.getCursorPos(obj);
        const year = parseInt(val.substring(0, 4));
        const month = val.substring(5, 7);
        const date = parseInt(val.substring(8, 10));

        //删除的情况
        if (this.currentKeyCode === 8) {
          if (pos === 4 || pos === 7) {
            this.defaultValue =
              this.defaultValue.substring(0, pos) +
              "-" +
              this.defaultValue.substring(pos + 1, 10);
          } else {
            this.defaultValue =
              this.defaultValue.substring(0, pos) +
              "0" +
              this.defaultValue.substring(pos + 1, 10);
          }

          setTimeout(() => {
            that.setCursorPos(obj, pos); //设置光标
          }, 20);
          return;
        }
        // 非删除的情况
        if (pos < 11) {
          let reg = /^[0-9-]*$/;
          if (!reg.test(val)) {
            //只允许输入数字和-
            setTimeout(() => {
              that.setCursorPos(obj, pos - 1); //设置光标
            }, 20);
            return;
          }
          switch (pos) {
            case 4: //碰到横杆时,自动多跳转一位
              this.defaultValue =
                val.substring(0, pos) + this.defaultValue.substring(pos, 10);
              setTimeout(() => {
                that.setCursorPos(obj, pos + 1); //设置光标
              }, 20);
              break;
            case 6: //校验月份位,月份首位不能大于1,一旦大于1,则月份自动调整为0开头的月份,然后跳转到日期位
              if (val.substring(pos - 1, pos) > 1) {
                this.defaultValue =
                  val.substring(0, pos - 1) +
                  "0" +
                  val.substring(pos - 1, pos) +
                  this.defaultValue.substring(pos + 1, 10);
                setTimeout(() => {
                  that.setCursorPos(obj, 8); //设置光标到日期处
                }, 20);
              } else {
                this.defaultValue =
                  val.substring(0, pos) + this.defaultValue.substring(pos, 10);
                setTimeout(() => {
                  that.setCursorPos(obj, pos); //设置光标
                }, 20);
              }
              break;
            case 7: //校验月份个位,如果首位是1,则个位最大不能超过2
              if (val.substring(5, 6) === "1" && val.substring(6, 7) > "2") {
                this.defaultValue =
                  val.substring(0, pos - 1) +
                  "2" +
                  this.defaultValue.substring(pos, 10);
                setTimeout(() => {
                  that.setCursorPos(obj, pos + 1); //设置光标
                }, 20);
              } else {
                this.defaultValue =
                  val.substring(0, pos) + this.defaultValue.substring(pos, 10);
                setTimeout(() => {
                  that.setCursorPos(obj, pos + 1); //设置光标
                }, 20);
              }
              break;
            case 9: //校验日期位,如果是2月份,首位不能是3并且非闰年时,末尾不能为9
              if (val.substring(5, 7) === "02") {
                //2月份
                if (val.substring(pos - 1, pos) > 2) {
                  this.defaultValue =
                    val.substring(0, pos - 1) +
                    "0" +
                    val.substring(pos - 1, pos) +
                    this.defaultValue.substring(pos + 1, 10);
                  setTimeout(() => {
                    that.setCursorPos(obj, 11); //设置光标到末尾处
                  }, 20);
                } else {
                  this.defaultValue =
                    val.substring(0, pos) +
                    this.defaultValue.substring(pos, 10);
                  setTimeout(() => {
                    that.setCursorPos(obj, pos); //设置光标
                  }, 20);
                }
              } else {
                //非2月份的情况
                if (val.substring(pos - 1, pos) > 3) {
                  this.defaultValue =
                    val.substring(0, pos - 1) +
                    "0" +
                    val.substring(pos - 1, pos) +
                    this.defaultValue.substring(pos + 1, 10);
                  setTimeout(() => {
                    that.setCursorPos(obj, 11); //设置光标到末尾处
                  }, 20);
                } else {
                  this.defaultValue =
                    val.substring(0, pos) +
                    this.defaultValue.substring(pos, 10);
                  setTimeout(() => {
                    that.setCursorPos(obj, pos); //设置光标
                  }, 20);
                }
              }
              break;
            case 10: //校验日期个位,如果是2月份,非闰年时,末尾不能为9
              if (month === "02") {
                //2月份
                if (date > 28) {
                  //非闰年
                  this.defaultValue = val.substring(0, pos) + "8";
                  setTimeout(() => {
                    that.setCursorPos(obj, pos); //设置光标
                  }, 20);
                } else {
                  this.defaultValue =
                    val.substring(0, pos) +
                    this.defaultValue.substring(pos, 10);
                  setTimeout(() => {
                    that.setCursorPos(obj, pos); //设置光标
                  }, 20);
                }
              } else {
                //非2月份的情况,如果是3开头,1\3\5\7\8\10\12则不能超过1,其他不能超过0
                if (
                  ["01", "03", "05", "07", "08", "10", "12"].indexOf(month) >
                    -1 &&
                  date > 31
                ) {
                  this.defaultValue = val.substring(0, 9) + "1";
                } else if (
                  ["02", "04", "06", "09", "11"].indexOf(month) > -1 &&
                  date > 30
                ) {
                  this.defaultValue = val.substring(0, 9) + "0";
                } else {
                  this.defaultValue =
                    val.substring(0, pos) +
                    this.defaultValue.substring(pos, 10);
                }
                setTimeout(() => {
                  that.setCursorPos(obj, pos); //设置光标
                }, 20);
              }
              break;
            default:
              this.defaultValue =
                val.substring(0, pos) + this.defaultValue.substring(pos, 10);
              setTimeout(() => {
                that.setCursorPos(obj, pos); //设置光标
              }, 20);
          }
        }

        this.lastPos = pos;
      }
    }
  },
  watch: {
    value() {
      if (this.value) {
        this.defaultValue = this.value.split(" ")[0];
      }
    }
  },
  created() {},
  mounted() {
    if (this.value) {
      this.defaultValue = this.value.split(" ")[0];
    }
    let that = this;
    document.getElementById(this.id).onkeydown = function(e) {
      that.currentKeyCode = e.keyCode;
    };
  },
  methods: {
    getCursorPos,
    setCursorPos,
    dateFormat10,
    //点击事件
    handleClick(e) {
      //先判断是否有选中的文本
      let userSelection = null;
      if (window.getSelection) {
        //一般浏览器
        userSelection = window.getSelection();
      } else if (document.selection) {
        //IE浏览器、Opera
        userSelection = document.selection.createRange();
      }
      //如果是选中文本事件,则直接返回
      if (userSelection.toString() !== "") {
        return;
      }
      let that = this;
      const obj = document.getElementById(this.id);
      setTimeout(() => {
        let pos = that.getCursorPos(obj);
        //-的位置不能被替换,自动多移动一位
        if (pos === 4 || pos === 7) {
          setTimeout(() => {
            that.setCursorPos(obj, pos + 1); //设置光标
          }, 100);
        }
      }, 100);
    },
    //获取焦点事件
    handleFocus() {
      this.handleClick();
    },
    handleInput() {
      if (this.defaultValue === "0000-00-00") {
        return;
      }
      this.$emit("input", this.defaultValue + " 00:00:00"); //触发 input 事件,并传入新值
    },
    //点击日期图标时触发
    handlePicker() {
      this.showPicker = true;
      if (this.defaultValue === "0000-00-00") {
        this.defaultValue = this.dateFormat10(new Date());
      }
      this.handleInput();
      let that = this;
      this.$nextTick(() => {
        that.$refs.datePicker.focus();
      });
    },
    //日期控件失去焦点时触发
    handleBlur() {
      this.showPicker = false;
      this.$emit("blur");
    }
  }
};
</script>

<style scoped>
.point {
  cursor: pointer;
}
</style>

<style></style>

代码里引用到的其他代码:

//获取光标的位置
export function getCursorPos(obj) {
  var pos = 0; // IE Support
  if (document.selection) {
    obj.focus();
    var sel = document.selection.createRange();
    sel.moveStart("character", -obj.value.length);
    pos = sel.text.length;
  } else if (obj.selectionStart || obj.selectionStart == "0") {
    // Firefox/Safari/Chrome/Opera support
    pos = obj.selectionEnd;
  }
  return pos;
}
//设置光标的位置
export function setCursorPos(obj, pos) {
  if (obj.setSelectionRange) {
    //Firefox/Safari/Chrome/Opera
    obj.focus();
    obj.setSelectionRange(pos, pos);
  } else if (obj.createTextRange) {
    // IE
    var range = obj.createTextRange();
    range.collapse(true);
    range.moveEnd("character", pos);
    range.moveStart("character", pos);
    range.select();
  }
}
/**
 * 日期格式化 yyyy-MM-dd
 */
export function dateFormat10(date) {
  if (date !== "Invalid Date") {
    let format = date.getFullYear() + "";
    if (date.getMonth() + 1 < 10) {
      format += "-0" + (date.getMonth() + 1);
    } else {
      format += "-" + (date.getMonth() + 1);
    }
    if (date.getDate() < 10) {
      format += "-0" + date.getDate();
    } else {
      format += "-" + date.getDate();
    }
    return format;
  }
  return "";
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容