在平时的工作中,对于日期控件,甲方爸爸们都有各种各样的定制化要求。
这不,又来了一个定制需求:
要求日期控件没有值的时候默认显示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 "";
}