From 3cf7cfd1de4022361d8e0bae254f9f6e23cc6403 Mon Sep 17 00:00:00 2001 From: 梁灏 <admin@aresn.com> Date: Mon, 19 Dec 2016 14:44:07 +0800 Subject: [PATCH] update DatePicker --- src/components/date-picker/base/date-table.vue | 67 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------ src/components/date-picker/panel/date-range.vue | 160 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---- src/components/date-picker/panel/date.vue | 20 ++++---------------- src/components/date-picker/panel/mixin.js | 18 ++++++++++++++++++ src/styles/components/date-picker.less | 40 +++++++++++++++++++++++++++++++++++++--- test/routers/date.vue | 48 +++++++++++++++++++++++++++++++++++++++++++----- 6 files changed, 319 insertions(+), 34 deletions(-) create mode 100644 src/components/date-picker/panel/mixin.js diff --git a/src/components/date-picker/base/date-table.vue b/src/components/date-picker/base/date-table.vue index ee83b6b..bfa9d5a 100644 --- a/src/components/date-picker/base/date-table.vue +++ b/src/components/date-picker/base/date-table.vue @@ -36,9 +36,7 @@ default () { return { endDate: null, - selecting: false, - row: null, - column: null + selecting: false }; } }, @@ -64,6 +62,8 @@ day = (day === 0 ? 7 : day); const today = clearHours(new Date()); // timestamp of today const selectDay = clearHours(new Date(this.value)); // timestamp of selected day + const minDay = clearHours(new Date(this.minDate)); + const maxDay = clearHours(new Date(this.maxDate)); const dateCountOfMonth = getDayCountOfMonth(date.getFullYear(), date.getMonth()); const dateCountOfLastMonth = getDayCountOfMonth(date.getFullYear(), (date.getMonth() === 0 ? 11 : date.getMonth() - 1)); @@ -75,7 +75,10 @@ text: '', type: '', selected: false, - disabled: false + disabled: false, + range: false, + start: false, + end: false }; if (day !== 7) { for (let i = 0; i < day; i++) { @@ -102,6 +105,10 @@ cell.text = i; cell.selected = time === selectDay; cell.disabled = typeof disabledDate === 'function' && disabledDate(new Date(time)); + cell.range = time >= minDay && time <= maxDay; + cell.start = this.minDate && time === minDay; + cell.end = this.maxDate && time === maxDay; + cells.push(cell); } @@ -156,6 +163,30 @@ if (this.selectionMode === 'range') { // todo + if (this.minDate && this.maxDate) { + const minDate = new Date(newDate.getTime()); + const maxDate = null; + this.$emit('on-pick', {minDate, maxDate}, false); + this.rangeState.selecting = true; + this.markRange(this.minDate); + } else if (this.minDate && !this.maxDate) { + if (newDate >= this.minDate) { + const maxDate = new Date(newDate.getTime()); + this.rangeState.selecting = false; + + this.$emit('on-pick', {minDate: this.minDate, maxDate}); + } else { + const minDate = new Date(newDate.getTime()); + + this.$emit('on-pick', {minDate, maxDate: this.maxDate}, false); + } + } else if (!this.minDate) { + const minDate = new Date(newDate.getTime()); + + this.$emit('on-pick', {minDate, maxDate: this.maxDate}, false); + this.rangeState.selecting = true; + this.markRange(this.minDate); + } } else { this.$emit('on-pick', newDate); } @@ -164,15 +195,39 @@ handleMouseMove () { }, + markRange (maxDate) { + const startDate = this.startDate; + if (!maxDate) { + maxDate = this.maxDate; + } + + const rows = this.rows; + const minDate = this.minDate; + for (var i = 0, k = rows.length; i < k; i++) { + const row = rows[i]; + for (var j = 0, l = row.length; j < l; j++) { + if (this.showWeekNumber && j === 0) continue; + + const cell = row[j]; + const index = i * 7 + j + (this.showWeekNumber ? -1 : 0); + const time = startDate.getTime() + DAY_DURATION * index; + + cell.inRange = minDate && time >= clearHours(minDate) && time <= clearHours(maxDate); + cell.start = minDate && time === clearHours(minDate.getTime()); + cell.end = maxDate && time === clearHours(maxDate.getTime()); + } + } + }, getCellCls (cell) { return [ `${prefixCls}-cell`, { - [`${prefixCls}-cell-selected`]: cell.selected, + [`${prefixCls}-cell-selected`]: cell.selected || cell.start || cell.end, [`${prefixCls}-cell-disabled`]: cell.disabled, [`${prefixCls}-cell-today`]: cell.type === 'today', [`${prefixCls}-cell-prev-month`]: cell.type === 'prev-month', - [`${prefixCls}-cell-next-month`]: cell.type === 'next-month' + [`${prefixCls}-cell-next-month`]: cell.type === 'next-month', + [`${prefixCls}-cell-range`]: cell.range && !cell.start && !cell.end } ] }, diff --git a/src/components/date-picker/panel/date-range.vue b/src/components/date-picker/panel/date-range.vue index a65ca94..3ef4899 100644 --- a/src/components/date-picker/panel/date-range.vue +++ b/src/components/date-picker/panel/date-range.vue @@ -1,27 +1,179 @@ <template> <div :class="classes"> - + <div :class="[prefixCls + '-sidebar']" v-if="shortcuts.length"> + <div + :class="[prefixCls + '-shortcut']" + v-for="shortcut in shortcuts" + @click="handleShortcutClick(shortcut)">{{ shortcut.text }}</div> + </div> + <div :class="[prefixCls + '-body']"> + <div :class="[prefixCls + '-content', prefixCls + '-content-left']"> + <div :class="[datePrefixCls + '-header']" v-show="currentView !== 'time'"> + <span + :class="iconBtnCls('prev', '-double')" + @click="prevYear"><Icon type="ios-arrow-left"></Icon></span> + <span + :class="iconBtnCls('prev')" + @click="prevMonth" + v-show="currentView === 'date'"><Icon type="ios-arrow-left"></Icon></span> + <span + :class="[datePrefixCls + '-header-label']" + @click="showYearPicker">{{ leftYear }} 年</span> + <span + :class="[datePrefixCls + '-header-label']" + @click="showMonthPicker" + v-show="currentView === 'date'">{{ leftMonth + 1 }} 月</span> + </div> + <date-table + v-show="currentView === 'date'" + :year="leftYear" + :month="leftMonth" + :date="date" + :min-date="minDate" + :max-date="maxDate" + :range-state="rangeState" + :selection-mode="selectionMode" + :disabled-date="disabledDate" + @on-pick="handleDatePick"></date-table> + </div> + <div :class="[prefixCls + '-content', prefixCls + '-content-right']"> + <div :class="[datePrefixCls + '-header']" v-show="currentView !== 'time'"> + <span + :class="[datePrefixCls + '-header-label']" + @click="showYearPicker">{{ rightYear }} 年</span> + <span + :class="[datePrefixCls + '-header-label']" + @click="showMonthPicker" + v-show="currentView === 'date'">{{ rightMonth + 1 }} 月</span> + <span + :class="iconBtnCls('next', '-double')" + @click="nextYear"><Icon type="ios-arrow-right"></Icon></span> + <span + :class="iconBtnCls('next')" + @click="nextMonth" + v-show="currentView === 'date'"><Icon type="ios-arrow-right"></Icon></span> + </div> + <date-table + v-show="currentView === 'date'" + :year="rightYear" + :month="rightMonth" + :date="rightDate" + :min-date="minDate" + :max-date="maxDate" + :range-state="rangeState" + :selection-mode="selectionMode" + :disabled-date="disabledDate" + @on-pick="handleDatePick"></date-table> + </div> + </div> </div> </template> <script> + import Icon from '../../icon/icon.vue'; + import DateTable from '../base/date-table.vue'; + import { toDate } from '../util'; + + import Mixin from './mixin'; + const prefixCls = 'ivu-picker-panel'; const datePrefixCls = 'ivu-date-picker'; export default { - props: {}, + mixins: [Mixin], + components: { Icon, DateTable }, data () { - return {} + return { + prefixCls: prefixCls, + datePrefixCls: datePrefixCls, + shortcuts: [], + date: new Date(), + value: '', + minDate: '', + maxDate: '', + rangeState: { + endDate: null, + selecting: false + }, + showTime: false, + disabledDate: '', + currentView: 'date', + selectionMode: 'range' + } }, computed: { classes () { return [ `${prefixCls}-body-wrapper`, + `${datePrefixCls}-with-range`, { [`${prefixCls}-with-sidebar`]: this.shortcuts.length } ] + }, + leftYear() { + return this.date.getFullYear(); + }, + leftMonth() { + return this.date.getMonth(); + }, + rightYear() { + return this.rightDate.getFullYear(); + }, + rightMonth() { + return this.rightDate.getMonth(); + }, + rightDate() { + const newDate = new Date(this.date); + const month = newDate.getMonth(); + newDate.setDate(1); + + if (month === 11) { + newDate.setFullYear(newDate.getFullYear() + 1); + newDate.setMonth(0); + } else { + newDate.setMonth(month + 1); + } + return newDate; + } + }, + watch: { + value(newVal) { + if (!newVal) { + this.minDate = null; + this.maxDate = null; + } else if (Array.isArray(newVal)) { + this.minDate = newVal[0] ? toDate(newVal[0]) : null; + this.maxDate = newVal[1] ? toDate(newVal[1]) : null; + if (this.minDate) this.date = new Date(this.minDate); +// this.handleConfirm(true); // todo 稍后测试 + } } }, - methods: {} + methods: { + prevYear () { + + }, + nextYear () { + + }, + prevMonth () { + + }, + nextMonth () { + + }, + showYearPicker () { + + }, + showMonthPicker () { + + }, + handleDatePick () { + + }, + handleConfirm(visible) { + this.$emit('on-pick', [this.minDate, this.maxDate], visible); + } + } } </script> \ No newline at end of file diff --git a/src/components/date-picker/panel/date.vue b/src/components/date-picker/panel/date.vue index 5bdfcf3..31ffaf5 100644 --- a/src/components/date-picker/panel/date.vue +++ b/src/components/date-picker/panel/date.vue @@ -1,6 +1,6 @@ <template> <div :class="classes"> - <div :class="[prefixCls + '-sidebar']" v-if="shortcuts"> + <div :class="[prefixCls + '-sidebar']" v-if="shortcuts.length"> <div :class="[prefixCls + '-shortcut']" v-for="shortcut in shortcuts" @@ -67,10 +67,13 @@ import MonthTable from '../base/month-table.vue'; import { formatDate, parseDate } from '../util'; + import Mixin from './mixin'; + const prefixCls = 'ivu-picker-panel'; const datePrefixCls = 'ivu-date-picker'; export default { + mixins: [Mixin], components: { Icon, DateTable, YearTable, MonthTable }, data () { return { @@ -114,13 +117,9 @@ if (!newVal) return; newVal = new Date(newVal); if (!isNaN(newVal)) { - // todo -// if (typeof this.disabledDate === 'function' && this.disabledDate(new Date(newVal))) return; - this.date = newVal; this.year = newVal.getFullYear(); this.month = newVal.getMonth(); -// this.$emit('on-pick', newVal, true); } } }, @@ -129,17 +128,6 @@ this.date = new Date(); this.$emit('on-pick', ''); }, - handleShortcutClick (shortcut) { - if (shortcut.value) this.$emit('on-pick', shortcut.value()); - if (shortcut.onClick) shortcut.onClick(this); - }, - iconBtnCls (direction, type = '') { - return [ - `${prefixCls}-icon-btn`, - `${datePrefixCls}-${direction}-btn`, - `${datePrefixCls}-${direction}-btn-arrow${type}`, - ] - }, resetDate () { this.date = new Date(this.date); }, diff --git a/src/components/date-picker/panel/mixin.js b/src/components/date-picker/panel/mixin.js new file mode 100644 index 0000000..1e0e353 --- /dev/null +++ b/src/components/date-picker/panel/mixin.js @@ -0,0 +1,18 @@ +const prefixCls = 'ivu-picker-panel'; +const datePrefixCls = 'ivu-date-picker'; + +export default { + methods: { + iconBtnCls (direction, type = '') { + return [ + `${prefixCls}-icon-btn`, + `${datePrefixCls}-${direction}-btn`, + `${datePrefixCls}-${direction}-btn-arrow${type}`, + ] + }, + handleShortcutClick (shortcut) { + if (shortcut.value) this.$emit('on-pick', shortcut.value()); + if (shortcut.onClick) shortcut.onClick(this); + } + } +} \ No newline at end of file diff --git a/src/styles/components/date-picker.less b/src/styles/components/date-picker.less index 1270c03..66dba3b 100644 --- a/src/styles/components/date-picker.less +++ b/src/styles/components/date-picker.less @@ -1,6 +1,8 @@ @date-picker-prefix-cls: ~"@{css-prefix}date-picker"; @picker-prefix-cls: ~"@{css-prefix}picker"; +@date-picker-cells-width: 196px; + .@{date-picker-prefix-cls} { position: relative; .@{select-dropdown-prefix-cls} { @@ -10,7 +12,7 @@ max-height: none; } &-cells{ - width: 196px; + width: @date-picker-cells-width; margin: 10px; span{ display: inline-block; @@ -81,7 +83,27 @@ } } } - &-selected,&-selected:hover { + &-range{ + position: relative; + em{ + position: relative; + z-index: 1; + } + &:before{ + content: ''; + display: block; + background: @date-picker-cell-hover-bg; + border-radius: 0; + border: 0; + position: absolute; + top: 2px; + bottom: 2px; + left: 0; + right: 0; + } + } + &-selected,&-selected:hover + { em{ background: @primary-color; color: #fff; @@ -93,7 +115,8 @@ color: @btn-disable-bg; } } - &-today&-selected{ + &-today&-selected + { em{ &:after{ background: #fff; @@ -151,6 +174,17 @@ } } } + + &-with-range{ + .@{picker-prefix-cls}-panel{ + &-body{ + min-width: (@date-picker-cells-width + 20) * 2; + } + &-content{ + float: left; + } + } + } } .@{picker-prefix-cls} { diff --git a/test/routers/date.vue b/test/routers/date.vue index 518b4ad..88e79f0 100644 --- a/test/routers/date.vue +++ b/test/routers/date.vue @@ -1,5 +1,5 @@ <template> - <div style="margin: 150px"> + <div style="margin: 50px"> <br> <row> <i-col span="8"> @@ -11,11 +11,16 @@ :options="options" @on-change="change" :format="format" - :editable="false" @on-open-change="change2"></date-picker> </i-col> <i-col span="8"> - <date-picker type="daterange" style="width:200px" placeholder="请选择日期" :value.sync="value2" :options="options2"></date-picker> + <date-picker + type="daterange" + style="width:200px" + placeholder="请选择日期" + :value.sync="value2" + align="right" + :options="options2"></date-picker> </i-col> </row> </div> @@ -26,9 +31,42 @@ return { // value: new Date(), value: '2016-12-25', - value2: '', + value2: ['2016-12-17', '2017-01-05'], options2: { - + shortcuts: [ + { + text: '今天', + value () { +// return new Date(); + return '1/2/19' + }, + onClick (picker) { + console.log('点击了今天'); + } + }, + { + text: '昨天', + value () { + const date = new Date(); + date.setTime(date.getTime() - 3600 * 1000 * 24); + return date; + }, + onClick () { + console.log('点击了昨天'); + } + }, + { + text: '最近三个月', + value () { + const date = new Date(); + date.setTime(date.getTime() - 3600 * 1000 * 24 * 7); + return date; + }, + onClick () { + console.log('点击了一周前'); + } + } + ] }, options: { disabledDate(time) { -- libgit2 0.21.4