vue 時間選擇器組件
阿新 • • 發佈:2018-06-20
emp str else template route spl efault emit child
vue 時間選擇器組件
組件效果:
單文件組件:
<template> <div class="date-pickers"> <!--date為computed計算屬性中得到的值 focus調用初始化日期方法--> <input type="text" placeholder="選擇日期" @focus="trueDateBox" :value="date" readonly/> <!--基於ATUI的輸入框,和input沒有太大區別--> <!--<at-input type="data" placeholder="輸入提示" @focus="trueDateBox" :value="date" readonly style="width:200px;display: inline-block;"></at-input>--> <transition name="fade"> <div class="date-box" v-if="dateBoxFlag"> <div class="day-select" style="height:40px;text-align: center"> <div> <button @click="reduceYear"><<</button> <button @click="reduceMonth"><</button> </div> <div> <input type="text" @click="selected" v-model="year"/>年 <input type="text" @click="selected" v-model="month"/>月 </div> <div> <button @click="addMonth">></button> <button @click="addYear">>></button> </div> </div> <div class="day-screen"> <div style="padding: 0;margin: 0"> <span v-for="week in week">{{ week }}</span> </div> <div @click="selectDay" style="padding: 0;margin: 0"> <span v-for="day in previousMonth" class="previousMonth"> {{ day }} </span> <span v-for="day in monthDay[month - 1]" :class="isActive(day)" class="currentMonth">{{ day }}</span> <span v-for="day in nextMonth" class="nextMonth">{{ day }}</span> </div> </div> </div> </transition> </div> </template> <script> export default { name: ‘datePickers‘, data () { return { dateBoxFlag: false, year: 0, month: 0, day: 0, previousMonth: [], nextMonth: [], week: [‘日‘, ‘一‘, ‘二‘, ‘三‘, ‘四‘, ‘五‘, ‘六‘], monthDay: [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31], dateTime:"" } }, props: { oldTime: "" }, mounted:function () { console.log(this.oldTime) if (this.oldTime != null) { var date = new Date(parseInt(this.oldTime.replace("/Date(", "").replace(")/", ""), 10)); //月份為0-11,所以+1,月份小於10時補個0 var month = date.getMonth() + 1 < 10 ? "0" + (date.getMonth() + 1) : date.getMonth() + 1; var currentDate = date.getDate() < 10 ? "0" + date.getDate() : date.getDate(); this.year=date.getFullYear(); this.month=month; this.day=currentDate; this.$emit(‘datatime‘,this.date); } }, computed: { date () { if (this.year == 0 || this.month == 0 || this.day == 0) { return ‘‘; } return this.year + ‘-‘ + this.month + ‘-‘ + this.day; } }, watch: { year: function (val) { let reg = /^[1-9]\d*$/g; if (!reg.test(val)) { let date = new Date(); this.year = date.getFullYear(); } if (val < 0) { this.year = 1; } if (val > 10000) { this.year = 10000; } this.dayScreen(); }, month: function (val) { let reg = /^[1-9]\d*$/g; if (!reg.test(val)) { let date = new Date(); this.month = date.getMonth() + 1; } if (val < 1) { this.month = 1; } if (val > 12) { this.month = 12; } this.dayScreen(); }, }, methods: { // 突出顯示當前日期 isActive (index) { if (index == this.day) { return { active: true, } } }, // 顯示日期盒子並初始化 trueDateBox () { if (this.date === ‘‘) { let date = new Date(); this.year = date.getFullYear(); if (this.isLeapYear(this.year)) { this.monthDay[1] = 29; } else { this.monthDay[1] = 28; } this.month = date.getMonth() + 1; this.day = date.getDate(); } this.dayScreen(); this.dateBoxFlag = true; }, // 增減年份 addYear () { this.year++; if (this.isLeapYear(this.year)) { this.monthDay[1] = 29; } else { this.monthDay[1] = 28; } }, reduceYear () { this.year--; if (this.isLeapYear(this.year)) { this.monthDay[1] = 29; } else { this.monthDay[1] = 28; } }, // 增減月份 addMonth () { this.month++; if (this.month > 12) { this.month = 1; this.year++; } }, reduceMonth () { this.month--; if (this.month < 1) { this.month = 12; this.year--; } }, // 獲取input裏的文字 selected (e) { e.target.select(); }, // 選擇日期 selectDay (e) { let targetClass = e.target.className; if (targetClass == ‘previousMonth‘) { if (this.month == 1) { this.month = 12; this.year--; } else { this.month = this.month - 1; } this.day = parseInt(e.target.innerText); } else if (targetClass == ‘nextMonth‘) { if (this.month == 12) { this.month = 1; this.year++; } else { this.month = this.month + 1; } this.day = parseInt(e.target.innerText); } else { this.day = parseInt(e.target.innerText); } this.$emit(‘datatime‘,this.date); this.dateBoxFlag = false; }, // 日期顯示 dayScreen () { // 上一個月 let firstDate = new Date(this.year, this.month - 1, 1); let firstWeek = firstDate.getDay(); let preMonthDay = null; if (this.month == 1) { preMonthDay = this.monthDay[11]; } else { preMonthDay = this.monthDay[this.month - 2]; } for (let i = 0; i < preMonthDay; i++) { this.previousMonth[i] = i + 1; } if (firstWeek == 0) { this.previousMonth = this.previousMonth.slice(-7); } else { this.previousMonth = this.previousMonth.slice(-firstWeek); } // 下一個月 let endDate = new Date(this.year, this.month - 1, this.monthDay[this.month - 1]); let endWeek = endDate.getDay(); let nextMonthDay = null; if (this.month == 12) { nextMonthDay = this.monthDay[0]; } else { nextMonthDay = this.monthDay[this.month]; } for (let i = 0; i < nextMonthDay; i++) { this.nextMonth[i] = i + 1; } if (endWeek == 6) { this.nextMonth = this.nextMonth.slice(0, 7); } else { this.nextMonth = this.nextMonth.slice(0, 6 - endWeek); } }, // 判斷是否是閏年 isLeapYear (year) { return (year % 100 == 0 ? (year % 400 == 0 ? true : false) : (year % 4 == 0 ? true : false)); }, } } </script> <style> .date-pickers { width: 280px; position: relative; } .date-pickers > input { width: 50%; height: 20px; padding: 5px; } .date-pickers .fade-enter-active, .date-pickers .fade-leave-active { transition: all 0.5s; } .date-pickers .fade-enter, .date-pickers .fade-leave-active { opacity: 0; transform: translateY(-10px); } .date-pickers > .date-box { width: 100%; border: 1px solid #EAEAEA; border-radius: 5px; box-shadow: 2px 2px 2px #eee; background: white; position: absolute; bottom: 38px; left: 0px; z-index: 99; } .date-pickers > div div.day-select { display: flex; padding: 5px 0; height: 30px; line-height: 30px; color: #888888; border-bottom: 1px solid #ccc; } .date-pickers > div div.day-select input, .date-pickers > div div.day-select button { border: none; background: white; text-align: center; color: #888888; cursor: pointer; } .date-pickers > div div.day-select > div:nth-child(1), .date-pickers > div div.day-select > div:nth-child(3) { width: 20%; } .date-pickers > div div.day-select > div:nth-child(2) { width: 60%; display: flex; justify-content: center; } .date-pickers > div div.day-select > div:nth-child(2) input:hover { background: #eee; } .date-pickers > div div.day-select > div:nth-child(2) input:nth-child(1) { width: 50px; } .date-pickers > div div.day-select > div:nth-child(2) input:nth-child(2) { width: 30px; } .date-pickers > div div.day-screen > div { width: 280px; padding: 0 5px; display: flex; font-size: 14px; justify-content: flex-start; flex-wrap: wrap; } .date-pickers > div div.day-screen > div span { width: 40px; height: 40px; text-align: center; line-height: 40px; border-bottom: 1px solid #ccc; } .date-pickers > div div.day-screen > div:nth-child(1) { font-weight: bold; background: #F8F8F8; } .date-pickers > div div.day-screen > div:nth-child(2) span { cursor: pointer; color: black; } .date-pickers > div div.day-screen > div:nth-child(2) span:hover, .date-pickers > div div.day-screen > div:nth-child(2) span.active { background: #21A5EF; color: white; } .date-pickers > div div.day-screen > div:nth-child(2) span.previousMonth, .date-pickers > div div.day-screen > div:nth-child(2) span.nextMonth { color: #888888; } /*# sourceMappingURL=style.css.map */ </style>
vue引用該單文件組件,會在頁面顯示一個輸入框,點擊後出現日期選擇器。但是頁面調用需要獲取父組件的默認值並向父組件傳遞日期選擇結果。(默認為空時可以不向子組件傳值)
<datePickers v-on:datatime="datatime" :oldTime="$store.state.Jtnc.seeobjs.DJSJ" v-if="isRouterAlive" class="inputStyle" ></datePickers>
v-on:datatime="datatime"向子組件傳遞了一個方法,子組件調用方法後可將選定日期值值傳回父組件。父組件方法:datatime
/*時間處理*/ datatime(theTime){ this.modifyModel.DJSJ = theTime; },
子組件調用(在選擇日期的方法selectDay中調用):
this.$emit(‘datatime‘,this.date);
:oldTime="$store.state.Jtnc.seeobjs.DJSJ"將默認的日期值傳入子組件,子組件通過props接收,看到組件時將看到默認日期。
props: { oldTime: "" }
v-if="isRouterAlive"為強制刷新組件的開關,由於該組件會在打開頁面時加載,而默認日期如果在打開模態框時傳入,所以在打開模態框時強行刷新組件,可看到默認日期。
將數據渲染在模態框中是調用this.reload()刷新組件。(https://www.cnblogs.com/s313139232/p/9176820.html)
/*組件刷新*/ reload () { this.isRouterAlive = false; this.$nextTick(() => (this.isRouterAlive = true)) },
組件源代碼:
.vue文件:
<template> <div class="date-pickers"> <input type="text" placeholder="選擇日期" @focus="trueDateBox" :value="date" readonly /> <transition name="fade"> <div class="date-box" v-if="dateBoxFlag"> <div class="day-select"> <div> <button @click="reduceYear">«</button> <button @click="reduceMonth"><</button> </div> <div> <input type="text" @click="selected" v-model="year" />年 <input type="text" @click="selected" v-model="month" />月 </div> <div> <button @click="addMonth">></button> <button @click="addYear">»</button> </div> </div> <div class="day-screen"> <div> <span v-for="week in week">{{ week }}</span> </div> <div @click="selectDay"> <span v-for="day in previousMonth" class="previousMonth"> {{ day }} </span> <span v-for="day in monthDay[month - 1]" v-bind:class="isActive(day)" class="currentMonth">{{ day }}</span> <span v-for="day in nextMonth" class="nextMonth">{{ day }}</span> </div> </div> </div> </transition> </div> </template> <script> export default { name: ‘datePickers‘, data () { return { dateBoxFlag: false, year: 0, month: 0, day: 0, previousMonth: [], nextMonth: [], week: [‘日‘, ‘一‘, ‘二‘, ‘三‘, ‘四‘, ‘五‘, ‘六‘], monthDay: [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31], } }, computed: { date () { if (this.year == 0 || this.month == 0 || this.day == 0) { return ‘‘; } return this.year + ‘-‘ + this.month + ‘-‘ + this.day; } }, watch: { year: function (val) { let reg = /^[1-9]\d*$/g; if (!reg.test(val)) { let date = new Date(); this.year = date.getFullYear(); } if (val < 0) { this.year = 1; } if (val > 10000) { this.year = 10000; } this.dayScreen(); }, month: function (val) { let reg = /^[1-9]\d*$/g; if (!reg.test(val)) { let date = new Date(); this.month = date.getMonth() + 1; } if (val < 1) { this.month = 1; } if (val > 12) { this.month = 12; } this.dayScreen(); }, }, methods: { // 突出顯示當前日期 isActive (index) { if (index == this.day) { return { active: true, } } }, // 顯示日期盒子並初始化 trueDateBox () { if (this.date === ‘‘) { let date = new Date(); this.year = date.getFullYear(); if (this.isLeapYear(this.year)) { this.monthDay[1] = 29; } else { this.monthDay[1] = 28; } this.month = date.getMonth() + 1; this.day = date.getDate(); } this.dayScreen(); this.dateBoxFlag = true; }, // 增減年份 addYear () { this.year++; if (this.isLeapYear(this.year)) { this.monthDay[1] = 29; } else { this.monthDay[1] = 28; } }, reduceYear () { this.year--; if (this.isLeapYear(this.year)) { this.monthDay[1] = 29; } else { this.monthDay[1] = 28; } }, // 增減月份 addMonth () { this.month++; if (this.month > 12) { this.month = 1; this.year++; } }, reduceMonth () { this.month--; if (this.month < 1) { this.month = 12; this.year--; } }, // 獲取input裏的文字 selected (e) { e.target.select(); }, // 選擇日期 selectDay (e) { let targetClass = e.target.className; if (targetClass == ‘previousMonth‘) { if (this.month == 1) { this.month = 12; this.year--; } else { this.month = this.month - 1; } this.day = parseInt(e.target.innerText); } else if (targetClass == ‘nextMonth‘) { if (this.month == 12) { this.month = 1; this.year++; } else { this.month = this.month + 1; } this.day = parseInt(e.target.innerText); } else { this.day = parseInt(e.target.innerText); } this.dateBoxFlag = false; }, // 日期顯示 dayScreen () { // 上一個月 let firstDate = new Date(this.year, this.month - 1, 1); let firstWeek = firstDate.getDay(); let preMonthDay = null; if (this.month == 1) { preMonthDay = this.monthDay[11]; } else { preMonthDay = this.monthDay[this.month - 2]; } for (let i = 0; i < preMonthDay; i++) { this.previousMonth[i] = i + 1; } if (firstWeek == 0) { this.previousMonth = this.previousMonth.slice(-7); } else { this.previousMonth = this.previousMonth.slice(-firstWeek); } // 下一個月 let endDate = new Date(this.year, this.month - 1, this.monthDay[this.month - 1]); let endWeek = endDate.getDay(); let nextMonthDay = null; if (this.month == 12) { nextMonthDay = this.monthDay[0]; } else { nextMonthDay = this.monthDay[this.month]; } for (let i = 0; i < nextMonthDay; i++) { this.nextMonth[i] = i + 1; } if (endWeek == 6) { this.nextMonth = this.nextMonth.slice(0, 7); } else { this.nextMonth = this.nextMonth.slice(0, 6 - endWeek); } }, // 判斷是否是閏年 isLeapYear (year) { return (year % 100 == 0 ? (year % 400 == 0 ? true : false) : (year % 4 == 0 ? true : false)); }, } } </script> <style lang="scss"> .date-pickers { width: 280px; padding: 5px; position: relative; >input { width: 50%; height: 20px; padding: 5px; } .fade-enter-active, .fade-leave-active { transition: all 0.5s; } .fade-enter, .fade-leave-active { opacity: 0; transform: translateY(-10px); } >div { width: 100%; border: 1px solid #EAEAEA; border-radius: 5px; box-shadow: 2px 2px 2px #eee; background: white; position: absolute; top: 50px; left: 0px; z-index: 99; div.day-select { display: flex; padding: 5px 0; height: 30px; line-height: 30px; color: #888888; border-bottom: 1px solid #ccc; input, button { border: none; background: white; text-align: center; color: #888888; cursor: pointer; } >div:nth-child(1), >div:nth-child(3) { width: 20%; } >div:nth-child(2) { width: 60%; display: flex; justify-content: center; input:hover { background: #eee; } input:nth-child(1) { width: 50px; } input:nth-child(2) { width: 30px; } } } div.day-screen { >div { width: 280px; padding: 0 5px; display: flex; font-size: 14px; justify-content: flex-start; flex-wrap: wrap; span { width: 40px; height: 40px; text-align: center; line-height: 40px; border-bottom: 1px solid #ccc; } } >div:nth-child(1) { font-weight: bold; background: #F8F8F8; } >div:nth-child(2) { span { cursor: pointer; color: black; &:hover, &.active { background: #21A5EF; color: white; } } span.previousMonth, span.nextMonth { color: #888888; } } } } } </style>
組件js文件:
Vue.component(‘datepickers‘, { template: ` <div class="date-pickers"> <input type="text" placeholder="選擇日期" @focus="trueDateBox" :value="date" readonly /> <transition name="fade"> <div class="date-box" v-if="dateBoxFlag"> <div class="day-select"> <div> <button @click="reduceYear">«</button> <button @click="reduceMonth"><</button> </div> <div> <input type="text" @click="selected" v-model="year" />年 <input type="text" @click="selected" v-model="month" />月 </div> <div> <button @click="addMonth">></button> <button @click="addYear">»</button> </div> </div> <div class="day-screen"> <div> <span v-for="week in week">{{ week }}</span> </div> <div @click="selectDay"> <span v-for="day in previousMonth" class="previousMonth"> {{ day }} </span> <span v-for="day in monthDay[month - 1]" v-bind:class="isActive(day)" class="currentMonth">{{ day }}</span> <span v-for="day in nextMonth" class="nextMonth">{{ day }}</span> </div> </div> </div> </transition> </div> `, name: ‘datePickers‘, data() { return { dateBoxFlag: false, year: 0, month: 0, day: 0, previousMonth: [], nextMonth: [], week: [‘日‘, ‘一‘, ‘二‘, ‘三‘, ‘四‘, ‘五‘, ‘六‘], monthDay: [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31], } }, computed: { date () { if (this.year == 0 || this.month == 0 || this.day == 0) { return ‘‘; } return this.year + ‘-‘ + this.month + ‘-‘ + this.day; }, }, watch: { year: function (val) { let reg = /^[1-9]\d*$/g; if (!reg.test(val)) { let date = new Date(); this.year = date.getFullYear(); } if (val < 0) { this.year = 1; } if (val > 10000) { this.year = 10000; } this.dayScreen(); }, month: function (val) { let reg = /^[1-9]\d*$/g; if (!reg.test(val)) { let date = new Date(); this.month = date.getMonth() + 1; } if (val < 1) { this.month = 1; } if (val > 12) { this.month = 12; } this.dayScreen(); }, }, methods: { // 突出顯示當前日期 isActive (index) { if (index == this.day) { return { active: true, } } }, // 顯示日期盒子並初始化 trueDateBox() { if (this.date == ‘‘) { let date = new Date(); this.year = date.getFullYear(); if (this.isLeapYear(this.year)) { this.monthDay[1] = 29; } else { this.monthDay[1] = 28; } this.month = date.getMonth() + 1; this.day = date.getDate(); } this.dayScreen(); this.dateBoxFlag = true; }, // 增減年份 addYear() { this.year++; if (this.isLeapYear(this.year)) { this.monthDay[1] = 29; } else { this.monthDay[1] = 28; } }, reduceYear() { this.year--; if (this.isLeapYear(this.year)) { this.monthDay[1] = 29; } else { this.monthDay[1] = 28; } }, // 增減月份 addMonth() { this.month++; if (this.month > 12) { this.month = 1; this.year++; } }, reduceMonth() { this.month--; if (this.month < 1) { this.month = 12; this.year--; } }, // 獲取input裏的文字 selected(e) { e.target.select(); }, // 選擇日期 selectDay(e) { let targetClass = e.target.className; if (targetClass == ‘previousMonth‘) { if (this.month == 1) { this.month = 12; this.year--; } else { this.month = this.month - 1; } this.day = parseInt(e.target.innerText); } else if (targetClass == ‘nextMonth‘) { if (this.month == 12) { this.month = 1; this.year++; } else { this.month = this.month + 1; } this.day = parseInt(e.target.innerText); } else { this.day = parseInt(e.target.innerText); } this.dateBoxFlag = false; }, // 日期顯示 dayScreen() { // 上一個月 let firstDate = new Date(this.year, this.month - 1, 1); let firstWeek = firstDate.getDay(); let preMonthDay = null; if (this.month == 1) { preMonthDay = this.monthDay[11]; } else { preMonthDay = this.monthDay[this.month - 2]; } for (let i = 0; i < preMonthDay; i++) { this.previousMonth[i] = i + 1; } if (firstWeek == 0) { this.previousMonth = this.previousMonth.slice(-7); } else { this.previousMonth = this.previousMonth.slice(-firstWeek); } // 下一個月 let endDate = new Date(this.year, this.month - 1, this.monthDay[this.month - 1]); let endWeek = endDate.getDay(); let nextMonthDay = null; if (this.month == 12) { nextMonthDay = this.monthDay[0]; } else { nextMonthDay = this.monthDay[this.month]; } for (let i = 0; i < nextMonthDay; i++) { this.nextMonth[i] = i + 1; } if (endWeek == 6) { this.nextMonth = this.nextMonth.slice(0, 7); } else { this.nextMonth = this.nextMonth.slice(0, 6 - endWeek); } }, // 判斷是否是閏年 isLeapYear(year) { return (year % 100 == 0 ? (year % 400 == 0 ? true : false) : (year % 4 == 0 ? true : false)); }, } });
css文件:
.date-pickers { width: 280px; padding: 5px; position: relative; } .date-pickers > input { width: 50%; height: 20px; padding: 5px; } .date-pickers .fade-enter-active, .date-pickers .fade-leave-active { transition: all 0.5s; } .date-pickers .fade-enter, .date-pickers .fade-leave-active { opacity: 0; transform: translateY(-10px); } .date-pickers > div { width: 100%; border: 1px solid #EAEAEA; border-radius: 5px; box-shadow: 2px 2px 2px #eee; background: white; position: absolute; top: 50px; left: 0px; z-index: 99; } .date-pickers > div div.day-select { display: flex; padding: 5px 0; height: 30px; line-height: 30px; color: #888888; border-bottom: 1px solid #ccc; } .date-pickers > div div.day-select input, .date-pickers > div div.day-select button { border: none; background: white; text-align: center; color: #888888; cursor: pointer; } .date-pickers > div div.day-select > div:nth-child(1), .date-pickers > div div.day-select > div:nth-child(3) { width: 20%; } .date-pickers > div div.day-select > div:nth-child(2) { width: 60%; display: flex; justify-content: center; } .date-pickers > div div.day-select > div:nth-child(2) input:hover { background: #eee; } .date-pickers > div div.day-select > div:nth-child(2) input:nth-child(1) { width: 50px; } .date-pickers > div div.day-select > div:nth-child(2) input:nth-child(2) { width: 30px; } .date-pickers > div div.day-screen > div { width: 280px; padding: 0 5px; display: flex; font-size: 14px; justify-content: flex-start; flex-wrap: wrap; } .date-pickers > div div.day-screen > div span { width: 40px; height: 40px; text-align: center; line-height: 40px; border-bottom: 1px solid #ccc; } .date-pickers > div div.day-screen > div:nth-child(1) { font-weight: bold; background: #F8F8F8; } .date-pickers > div div.day-screen > div:nth-child(2) span { cursor: pointer; color: black; } .date-pickers > div div.day-screen > div:nth-child(2) span:hover, .date-pickers > div div.day-screen > div:nth-child(2) span.active { background: #21A5EF; color: white; } .date-pickers > div div.day-screen > div:nth-child(2) span.previousMonth, .date-pickers > div div.day-screen > div:nth-child(2) span.nextMonth { color: #888888; } /*# sourceMappingURL=style.css.map */
項目源代碼:https://github.com/huanghaibin91/Date-Pickers
原項目效果:https://huanghaibin91.github.io/Date-Pickers/
vue 時間選擇器組件