vue实现时间选择器,精确到秒
时间组件代码:/**时间选择器,精确到秒* <iic-datetime v-model="time"></iic-datetime>* time: new Date()*/Vue.component("iic-datetime", {props: {value: {type: [Date, String],default: ""},dateForma
·
时间组件代码:
/**时间选择器,精确到秒
* <iic-datetime v-model="time"></iic-datetime>
* time: new Date()
*/
Vue.component("iic-datetime", {
props: {
value: {
type: [Date, String],
default: ""
},
dateFormat: {//时间到天的格式
type: String,
default: "yyyy-MM-dd"
},
timeFormat: {//时间从小时到秒的格式
type: String,
default: "hh:mm:ss"
}
},
mounted: function() {
var dateNode = this.$refs.dateTimeRef;
var timeNode = this.$refs.timeRef;
var inputTimeNode = this.$refs.inputTimeRef;
var that = this;
window.addEventListener("click", function(e){
if (dateNode.contains(e.target)) {
if (!timeNode.contains(e.target) && !inputTimeNode.contains(e.target)) {
that.timePanelStatus = false;
}
} else {
that.panelState = false;
}
});
if (this.value) {
this.initDate( new Date(this.value) );
}
},
destroyed: function() {
window.removeEventListener("click", this.eventListener);
},
data: function() {
return {
fullTimeValue: "",//显示日期加精确到秒的时间
dateValue: "", // 输入框显示日期
timeValue: "",//时间选项
timePanelStatus: true,//时间选择面板是否展示
date: new Date().getDate(), // 当前日期
panelState: false, // 初始值,默认panel关闭
tmpMonth: new Date().getMonth(), // 临时月份,可修改
month: new Date().getMonth(),
tmpYear: new Date().getFullYear(), // 临时年份,可修改
weekList: [
{ label: "周一", value: 0 },
{ label: "周二", value: 1 },
{ label: "周三", value: 2 },
{ label: "周四", value: 3 },
{ label: "周五", value: 4 },
{ label: "周六", value: 5 },
{ label: "周天", value: 6 }
], // 周
monthList: [
{ label: "一月", value: 0 },
{ label: "二月", value: 1 },
{ label: "三月", value: 2 },
{ label: "四月", value: 3 },
{ label: "五月", value: 4 },
{ label: "六月", value: 5 },
{ label: "七月", value: 6 },
{ label: "八月", value: 7 },
{ label: "九月", value: 8 },
{ label: "十月", value: 9 },
{ label: "十一月", value: 10 },
{ label: "十二月", value: 11 }
], // 月
hourList: [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23],//小时
nowValue: 0, // 当前选中日期值
choseHour: 0,//选中的小时
choseMine: 1,
choseSec: 1,
panelType: "date" // 面板状态
}
},
watch: {
choseHour: function(){
this.freshDate();
},
choseMine: function(){
this.freshDate();
},
choseSec: function(){
this.freshDate();
}
},
computed: {
minuList: function(){
var minuList = [];
for (var i = 1; i <= 59; i++){
minuList.push(i);
}
return minuList;
},
secList: function(){
var secList = [];
for (var i = 1; i <= 59; i++){
secList.push(i);
}
return secList;
},
dateList: function(){
//获取当月的天数
var currentMonthLength = new Date(this.tmpYear, this.tmpMonth + 1, 0).getDate();
//先将当月的日期塞入dateList
var dateList = Array.from(
{ length: currentMonthLength },
function (val, index) {
return {
currentMonth: true,
value: index + 1
};
}
);
// 获取当月1号的星期是为了确定在1号前需要插多少天
var startDay = new Date(this.tmpYear, this.tmpMonth, 1).getDay();
// 确认上个月一共多少天
var previousMongthLength = new Date(this.tmpYear, this.tmpMonth, 0).getDate();
// 在1号前插入上个月日期
for (var i = 0, len = startDay; i < len; i++) {
dateList = [
{ previousMonth: true, value: previousMongthLength - i }
].concat(dateList);
}
// 补全剩余位置,至少14天,则 i < 15
for (var j = 1, item = 1; j < 15; j++, item++) {
dateList[dateList.length] = { nextMonth: true, value: j };
}
return dateList;
},
changeTmpMonth: function() {
return this.monthList[this.tmpMonth].label;
},
// 通过改变this.tmpYear则可以改变年份数组
yearList: function() {
return Array.from({ length: 12 }, function(value, index){
return this.tmpYear + index;
});
}
},
methods: {
initDate: function(initDate){
this.choseHour = initDate.getHours();
this.choseMine = initDate.getMinutes();
this.choseSec = initDate.getSeconds();
this.fullTimeValue = this.formatDate(initDate.getTime());
var dateTimeArr = this.fullTimeValue.split(" ");
this.dateValue = dateTimeArr[0];
this.timeValue = dateTimeArr[1];
},
setDateWithNow: function(){
this.initDate( new Date() );
},
togglePanel: function(){
this.panelState = !this.panelState;
},
hourScroll: function(evt){
var scrollTop = evt.target.scrollTop;
this.choseHour = window.parseInt(scrollTop / 20);
},
minuScroll: function(evt){
var scrollTop = evt.target.scrollTop;
this.choseMine = window.parseInt(scrollTop / 20) + 1;
},
secScroll: function(evt){
var scrollTop = evt.target.scrollTop;
this.choseSec = window.parseInt(scrollTop / 20) + 1;
},
openPanel: function(){
this.panelState = !this.panelState;
this.panelType = "date";
},
openTime: function(){
this.timePanelStatus = true;
},
selectYear: function(item){
this.tmpYear = item;
this.panelType = "month";
},
selectMonth: function(item){
this.tmpMonth = item.value;
this.panelType = "date";
},
freshDate: function(item){
if (item) {
// 赋值 当前 nowValue,用于控制样式突出显示当前月份日期
this.nowValue = item.value;
// 选择了上个月
if (item.previousMonth) this.tmpMonth--;
// 选择了下个月
if (item.nextMonth) this.tmpMonth++;
}
//计算出选中时间对象
var selectDay = new Date(this.tmpYear, this.tmpMonth, this.nowValue, this.choseHour, this.choseMine, this.choseSec);
// 格式日期为字符串后,赋值给 input
this.fullTimeValue = this.formatDate(selectDay.getTime());
var dateTimeArr = this.fullTimeValue.split(" ");
this.dateValue = dateTimeArr[0];
this.timeValue = dateTimeArr[1];
this.$emit("input", selectDay);
},
// 日期格式方法
formatDate: function(date) {
fmt = this.dateFormat + " " + this.timeFormat;
if (date === null || date === "null") {
return "--";
}
date = new Date(Number(date));
var o = {
"M+": date.getMonth() + 1, // 月份
"d+": date.getDate(), // 日
"h+": date.getHours(), // 小时
"m+": date.getMinutes(), // 分
"s+": date.getSeconds(), // 秒
"q+": Math.floor((date.getMonth() + 3) / 3), // 季度
S: date.getMilliseconds() // 毫秒
};
if (/(y+)/.test(fmt))
fmt = fmt.replace(
RegExp.$1,
(date.getFullYear() + "").substr(4 - RegExp.$1.length)
);
for (var k in o) {
if (new RegExp("(" + k + ")").test(fmt))
fmt = fmt.replace(
RegExp.$1,
RegExp.$1.length === 1
? o[k]
: ("00" + o[k]).substr(("" + o[k]).length)
);
}
return fmt;
},
validateDate: function(item) {
if (this.nowValue === item.value && item.currentMonth) {
return true;
}
},
left: function() {
if (this.panelType === "year") this.tmpYear--;
else {
if (this.tmpMonth === 0) {
this.tmpYear--;
this.tmpMonth = 11;
} else this.tmpMonth--;
}
},
leftBig: function() {
if (this.panelType === "year") {
this.tmpYear -= 12;
} else {
this.tmpYear--;
}
},
right: function() {
if (this.panelType === "year") {
this.tmpYear++;
} else {
if (this.tmpMonth === 11) {
this.tmpYear++;
this.tmpMonth = 0;
} else this.tmpMonth++;
}
},
rightBig: function() {
if (this.panelType === "year") {
this.tmpYear += 12;
} else {
this.tmpYear++;
}
},
},
template:
`<div ref="dateTimeRef" class="iic-input-date">
<input class="input date-value" v-model="fullTimeValue" @click="openPanel"/>
<div class="date-panel" v-show="panelState">
<div>
<input class="input input-date" v-model="dateValue"/>
<input class="input input-time" v-model="timeValue" ref="inputTimeRef" @click="openTime"/>
</div>
<div class="topbar">
<span @click="leftBig"><<</span>
<span @click="left"><</span>
<span class="year" @click="panelType = \'year\'">{{tmpYear}}</span>
<span class="month" @click="panelType = \'month\'">{{changeTmpMonth}}</span>
<span @click="right">></span>
<span @click="rightBig">>></span>
</div>
<div v-show="timePanelStatus" ref="timeRef" class="time-zone">
<div class="scroll-content">
<div @scroll="hourScroll" class="scroll-wrapper">
<ul ref="hourScollRef" class="time-scroll">
<li v-for="hour in hourList" :class="{'active': choseHour === hour}">{{hour}}</li>
</ul>
</div>
</div>
<div class="scroll-content">
<div @scroll="minuScroll" class="scroll-wrapper">
<ul ref="minuScrollRef" class="time-scroll">
<li v-for="minu in minuList" :class="{'active': choseMine === minu}">{{minu}}</li>
</ul>
</div>
</div>
<div class="scroll-content">
<div @scroll="secScroll" class="scroll-wrapper">
<ul ref="secScrollRef" class="time-scroll">
<li v-for="sec in secList" :class="{'active': choseSec === sec}">{{sec}}</li>
</ul>
</div>
</div>
<div class="bottom">
<button class="btn-ok" @click="timePanelStatus = false;">确认</button>
</div>
</div>
<div class="type-year" v-show="panelType === \'year\'">
<ul class="year-list">
<li v-for="(item, index) in yearList"
:key="index"
@click="selectYear(item)"
>
<span :class="{selected: item === tmpYear}" >{{item}}</span>
</li>
</ul>
</div>
<div class="type-year" v-show="panelType === \'month\'">
<ul class="year-list">
<li v-for="(item, index) in monthList"
:key="index"
@click="selectMonth(item)"
>
<span :class="{selected: item.value === tmpMonth}" >{{item.label}}</span>
</li>
</ul>
</div>
<div class="date-group" v-show="panelType === \'date\'">
<span v-for="(item, index) in weekList" :key="index" class="weekday">{{item.label}}</span>
<ul class="date-list">
<li v-for="(item, index) in dateList"
v-text="item.value"
:class="{preMonth: item.previousMonth, nextMonth: item.nextMonth,
selected: date === item.value && month === tmpMonth && item.currentMonth, invalid: validateDate(item)}"
:key="index"
@click="freshDate(item)">
</li>
</ul>
</div>
<div class="bottom">
<button @click="setDateWithNow">当前时间</button>
<button @click="togglePanel">确认</button>
</div>
</div>
</div>`
});
2:在vue实例中使用:
<div id="date">
<iic-datetime v-model="time"></iic-datetime>
</div>
<script>
new Vue({
el: "#date",
data: {
time: new Date()
},
watch: {
time: function(oldVal, newVal){
console.info(oldVal);
console.info(newVal);
}
},
});
</script>
样式:
<style>
/* datetime */
.iic-input-date .topbar {padding-top: 8px;}
.iic-input-date .topbar span {display: inline-block;width: 20px;height: 30px;line-height: 30px; color: #515a6e;cursor: pointer;}
.iic-input-date .topbar span:hover {color: #2d8cf0;}
.iic-input-date .topbar .year,
.topbar .month {width: 60px;}
.iic-input-date .year-list {height: 200px;width: 210px;}
.iic-input-date .year-list .selected {background: #2d8cf0;border-radius: 4px;color: #fff;}
.iic-input-date .year-list li {display: inline-block;width: 70px;height: 50px;line-height: 50px;border-radius: 10px;cursor: pointer;}
.iic-input-date .year-list span {display: inline-block;line-height: 16px;padding: 8px;}
.iic-input-date .year-list span:hover { background: #e1f0fe;}
.iic-input-date .weekday {display: inline-block; font-size: 13px;width: 30px; color: #c5c8ce;text-align: center;}
.iic-input-date {width: 260px;text-align: center;font-family: "Avenir", Helvetica, Arial, sans-serif;position: relative;}
.iic-input-date .date-panel {box-shadow: 0 0 8px #ccc;background: #fff;}
.iic-input-date ul {list-style: none; padding: 0;margin: 0;}
.iic-input-date .date-list { width: 210px;text-align: left;height: 180px; overflow: hidden;margin-top: 4px;}
.iic-input-date .date-list li { display: inline-block;width: 28px;height: 28px; line-height: 30px; text-align: center;cursor: pointer; color: #000;border: 1px solid #fff; border-radius: 4px;}
.iic-input-date .date-list .selected {border: 1px solid #2d8cf0;}
.iic-input-date .date-list .invalid { background: #2d8cf0; color: #fff;}
.iic-input-date .date-list .preMonth, .iic-input-date .date-list .nextMonth { color: #c5c8ce;}
.iic-input-date .date-list li:hover {background: #e1f0fe;}
.iic-input-date .date-panel .date-group{margin-left: 5px;}
.iic-input-date .input { display: inline-block; box-sizing: border-box; width: 45%; height: 32px;line-height: 1.5;padding: 4px 7px;font-size: 12px;border: 1px solid #dcdee2;border-radius: 4px;color: #515a6e;background-color: #fff;background-image: none;cursor: text;transition: border 0.2s ease-in-out, background 0.2s ease-in-out,box-shadow 0.2s ease-in-out;margin-bottom: 6px;}
.iic-input-date .date-value{width: 100%;}
.iic-input-date .input-date{left: 0;position: absolute; top: 36px;}
.iic-input-date .input-time{right: 0;position: absolute; top: 36px;}
.iic-input-date .time-zone{ top: 73px;
position: absolute;
width: 115px;
height: 130px;
background-color: white;
white-space: nowrap;
border: 1px solid #e4e7ed;
right: 0;}
.iic-input-date .time-zone::before{content: "";
top: 50%;
position: absolute;
margin-top: -15px;
height: 32px;
z-index: -1;
left: 0;
right: 0;
box-sizing: border-box;
padding-top: 6px;
text-align: left;
border-top: 1px solid #e4e7ed;
border-bottom: 1px solid #e4e7ed;}
.iic-input-date .scroll-content{overflow: hidden;height: 100px;width: 35px;display: inline-block;}
.iic-input-date .scroll-wrapper{overflow-y: scroll;display: inline-block;height: 100%;}
.iic-input-date .time-scroll::before, .iic-input-date .time-scroll::after{content: "";
display: block;
width: 100%;
height: 40px;}
.iic-input-date .bottom{height: 30px;
border-top: 1px solid #e4e4e4;
padding: 4px;
text-align: right;
box-sizing: border-box;
position: relative;}
.iic-input-date .bottom > button{border: 1px solid #dcdfe6;
cursor: pointer;
background-color: #fff;
border-radius: 3px;
font-size: 12px;}
.iic-input-date .time-zone .time-scroll{width: 35px;display: inline-block;overflow: hidden;}
.iic-input-date .time-scroll > li{height: 20px;cursor: pointer;color: #606266;font-size: 12px; line-height: 20px;}
.iic-input-date .time-scroll .active{color: #409eff;}
.iic-input-date .time-scroll >li:hover{background-color: #f5f7fa;}
.fadeDownBig-enter-active,
.fadeDownBig-leave-active,
.fadeInDownBig { -webkit-animation-duration: 0.5s; animation-duration: 0.5s; -webkit-animation-fill-mode: both; animation-fill-mode: both;}
.fadeDownBig-enter-active {-webkit-animation-name: fadeInDownBig; animation-name: fadeInDownBig;}
.fadeDownBig-leave-active {-webkit-animation-name: fadeOutDownBig; animation-name: fadeOutDownBig;}
@-webkit-keyframes fadeInDownBig {
from {
opacity: 0.8;
-webkit-transform: translate3d(0, -4px, 0);
transform: translate3d(0, -4px, 0);
}
to {
opacity: 1;
-webkit-transform: none;
transform: none;
}
}
@keyframes fadeInDownBig {
from {
opacity: 0.8;
-webkit-transform: translate3d(0, -4px, 0);
transform: translate3d(0, -4px, 0);
}
to {
opacity: 1;
-webkit-transform: none;
transform: none;
}
}
@-webkit-keyframes fadeOutDownBig {
from {
opacity: 1;
}
to {
opacity: 0.8;
-webkit-transform: translate3d(0, -4px, 0);
transform: translate3d(0, -4px, 0);
}
}
@keyframes fadeOutDownBig {
from {
opacity: 1;
}
to {
opacity: 0;
}
}
</style>
效果图:
更多推荐
已为社区贡献1条内容
所有评论(0)