Commit 3cf7cfd1de4022361d8e0bae254f9f6e23cc6403

Authored by 梁灏
1 parent e0cd7f90

update DatePicker

update DatePicker
src/components/date-picker/base/date-table.vue
... ... @@ -36,9 +36,7 @@
36 36 default () {
37 37 return {
38 38 endDate: null,
39   - selecting: false,
40   - row: null,
41   - column: null
  39 + selecting: false
42 40 };
43 41 }
44 42 },
... ... @@ -64,6 +62,8 @@
64 62 day = (day === 0 ? 7 : day);
65 63 const today = clearHours(new Date()); // timestamp of today
66 64 const selectDay = clearHours(new Date(this.value)); // timestamp of selected day
  65 + const minDay = clearHours(new Date(this.minDate));
  66 + const maxDay = clearHours(new Date(this.maxDate));
67 67  
68 68 const dateCountOfMonth = getDayCountOfMonth(date.getFullYear(), date.getMonth());
69 69 const dateCountOfLastMonth = getDayCountOfMonth(date.getFullYear(), (date.getMonth() === 0 ? 11 : date.getMonth() - 1));
... ... @@ -75,7 +75,10 @@
75 75 text: '',
76 76 type: '',
77 77 selected: false,
78   - disabled: false
  78 + disabled: false,
  79 + range: false,
  80 + start: false,
  81 + end: false
79 82 };
80 83 if (day !== 7) {
81 84 for (let i = 0; i < day; i++) {
... ... @@ -102,6 +105,10 @@
102 105 cell.text = i;
103 106 cell.selected = time === selectDay;
104 107 cell.disabled = typeof disabledDate === 'function' && disabledDate(new Date(time));
  108 + cell.range = time >= minDay && time <= maxDay;
  109 + cell.start = this.minDate && time === minDay;
  110 + cell.end = this.maxDate && time === maxDay;
  111 +
105 112 cells.push(cell);
106 113 }
107 114  
... ... @@ -156,6 +163,30 @@
156 163  
157 164 if (this.selectionMode === 'range') {
158 165 // todo
  166 + if (this.minDate && this.maxDate) {
  167 + const minDate = new Date(newDate.getTime());
  168 + const maxDate = null;
  169 + this.$emit('on-pick', {minDate, maxDate}, false);
  170 + this.rangeState.selecting = true;
  171 + this.markRange(this.minDate);
  172 + } else if (this.minDate && !this.maxDate) {
  173 + if (newDate >= this.minDate) {
  174 + const maxDate = new Date(newDate.getTime());
  175 + this.rangeState.selecting = false;
  176 +
  177 + this.$emit('on-pick', {minDate: this.minDate, maxDate});
  178 + } else {
  179 + const minDate = new Date(newDate.getTime());
  180 +
  181 + this.$emit('on-pick', {minDate, maxDate: this.maxDate}, false);
  182 + }
  183 + } else if (!this.minDate) {
  184 + const minDate = new Date(newDate.getTime());
  185 +
  186 + this.$emit('on-pick', {minDate, maxDate: this.maxDate}, false);
  187 + this.rangeState.selecting = true;
  188 + this.markRange(this.minDate);
  189 + }
159 190 } else {
160 191 this.$emit('on-pick', newDate);
161 192 }
... ... @@ -164,15 +195,39 @@
164 195 handleMouseMove () {
165 196  
166 197 },
  198 + markRange (maxDate) {
  199 + const startDate = this.startDate;
  200 + if (!maxDate) {
  201 + maxDate = this.maxDate;
  202 + }
  203 +
  204 + const rows = this.rows;
  205 + const minDate = this.minDate;
  206 + for (var i = 0, k = rows.length; i < k; i++) {
  207 + const row = rows[i];
  208 + for (var j = 0, l = row.length; j < l; j++) {
  209 + if (this.showWeekNumber && j === 0) continue;
  210 +
  211 + const cell = row[j];
  212 + const index = i * 7 + j + (this.showWeekNumber ? -1 : 0);
  213 + const time = startDate.getTime() + DAY_DURATION * index;
  214 +
  215 + cell.inRange = minDate && time >= clearHours(minDate) && time <= clearHours(maxDate);
  216 + cell.start = minDate && time === clearHours(minDate.getTime());
  217 + cell.end = maxDate && time === clearHours(maxDate.getTime());
  218 + }
  219 + }
  220 + },
167 221 getCellCls (cell) {
168 222 return [
169 223 `${prefixCls}-cell`,
170 224 {
171   - [`${prefixCls}-cell-selected`]: cell.selected,
  225 + [`${prefixCls}-cell-selected`]: cell.selected || cell.start || cell.end,
172 226 [`${prefixCls}-cell-disabled`]: cell.disabled,
173 227 [`${prefixCls}-cell-today`]: cell.type === 'today',
174 228 [`${prefixCls}-cell-prev-month`]: cell.type === 'prev-month',
175   - [`${prefixCls}-cell-next-month`]: cell.type === 'next-month'
  229 + [`${prefixCls}-cell-next-month`]: cell.type === 'next-month',
  230 + [`${prefixCls}-cell-range`]: cell.range && !cell.start && !cell.end
176 231 }
177 232 ]
178 233 },
... ...
src/components/date-picker/panel/date-range.vue
1 1 <template>
2 2 <div :class="classes">
3   -
  3 + <div :class="[prefixCls + '-sidebar']" v-if="shortcuts.length">
  4 + <div
  5 + :class="[prefixCls + '-shortcut']"
  6 + v-for="shortcut in shortcuts"
  7 + @click="handleShortcutClick(shortcut)">{{ shortcut.text }}</div>
  8 + </div>
  9 + <div :class="[prefixCls + '-body']">
  10 + <div :class="[prefixCls + '-content', prefixCls + '-content-left']">
  11 + <div :class="[datePrefixCls + '-header']" v-show="currentView !== 'time'">
  12 + <span
  13 + :class="iconBtnCls('prev', '-double')"
  14 + @click="prevYear"><Icon type="ios-arrow-left"></Icon></span>
  15 + <span
  16 + :class="iconBtnCls('prev')"
  17 + @click="prevMonth"
  18 + v-show="currentView === 'date'"><Icon type="ios-arrow-left"></Icon></span>
  19 + <span
  20 + :class="[datePrefixCls + '-header-label']"
  21 + @click="showYearPicker">{{ leftYear }} 年</span>
  22 + <span
  23 + :class="[datePrefixCls + '-header-label']"
  24 + @click="showMonthPicker"
  25 + v-show="currentView === 'date'">{{ leftMonth + 1 }} 月</span>
  26 + </div>
  27 + <date-table
  28 + v-show="currentView === 'date'"
  29 + :year="leftYear"
  30 + :month="leftMonth"
  31 + :date="date"
  32 + :min-date="minDate"
  33 + :max-date="maxDate"
  34 + :range-state="rangeState"
  35 + :selection-mode="selectionMode"
  36 + :disabled-date="disabledDate"
  37 + @on-pick="handleDatePick"></date-table>
  38 + </div>
  39 + <div :class="[prefixCls + '-content', prefixCls + '-content-right']">
  40 + <div :class="[datePrefixCls + '-header']" v-show="currentView !== 'time'">
  41 + <span
  42 + :class="[datePrefixCls + '-header-label']"
  43 + @click="showYearPicker">{{ rightYear }} 年</span>
  44 + <span
  45 + :class="[datePrefixCls + '-header-label']"
  46 + @click="showMonthPicker"
  47 + v-show="currentView === 'date'">{{ rightMonth + 1 }} 月</span>
  48 + <span
  49 + :class="iconBtnCls('next', '-double')"
  50 + @click="nextYear"><Icon type="ios-arrow-right"></Icon></span>
  51 + <span
  52 + :class="iconBtnCls('next')"
  53 + @click="nextMonth"
  54 + v-show="currentView === 'date'"><Icon type="ios-arrow-right"></Icon></span>
  55 + </div>
  56 + <date-table
  57 + v-show="currentView === 'date'"
  58 + :year="rightYear"
  59 + :month="rightMonth"
  60 + :date="rightDate"
  61 + :min-date="minDate"
  62 + :max-date="maxDate"
  63 + :range-state="rangeState"
  64 + :selection-mode="selectionMode"
  65 + :disabled-date="disabledDate"
  66 + @on-pick="handleDatePick"></date-table>
  67 + </div>
  68 + </div>
4 69 </div>
5 70 </template>
6 71 <script>
  72 + import Icon from '../../icon/icon.vue';
  73 + import DateTable from '../base/date-table.vue';
  74 + import { toDate } from '../util';
  75 +
  76 + import Mixin from './mixin';
  77 +
7 78 const prefixCls = 'ivu-picker-panel';
8 79 const datePrefixCls = 'ivu-date-picker';
9 80  
10 81 export default {
11   - props: {},
  82 + mixins: [Mixin],
  83 + components: { Icon, DateTable },
12 84 data () {
13   - return {}
  85 + return {
  86 + prefixCls: prefixCls,
  87 + datePrefixCls: datePrefixCls,
  88 + shortcuts: [],
  89 + date: new Date(),
  90 + value: '',
  91 + minDate: '',
  92 + maxDate: '',
  93 + rangeState: {
  94 + endDate: null,
  95 + selecting: false
  96 + },
  97 + showTime: false,
  98 + disabledDate: '',
  99 + currentView: 'date',
  100 + selectionMode: 'range'
  101 + }
14 102 },
15 103 computed: {
16 104 classes () {
17 105 return [
18 106 `${prefixCls}-body-wrapper`,
  107 + `${datePrefixCls}-with-range`,
19 108 {
20 109 [`${prefixCls}-with-sidebar`]: this.shortcuts.length
21 110 }
22 111 ]
  112 + },
  113 + leftYear() {
  114 + return this.date.getFullYear();
  115 + },
  116 + leftMonth() {
  117 + return this.date.getMonth();
  118 + },
  119 + rightYear() {
  120 + return this.rightDate.getFullYear();
  121 + },
  122 + rightMonth() {
  123 + return this.rightDate.getMonth();
  124 + },
  125 + rightDate() {
  126 + const newDate = new Date(this.date);
  127 + const month = newDate.getMonth();
  128 + newDate.setDate(1);
  129 +
  130 + if (month === 11) {
  131 + newDate.setFullYear(newDate.getFullYear() + 1);
  132 + newDate.setMonth(0);
  133 + } else {
  134 + newDate.setMonth(month + 1);
  135 + }
  136 + return newDate;
  137 + }
  138 + },
  139 + watch: {
  140 + value(newVal) {
  141 + if (!newVal) {
  142 + this.minDate = null;
  143 + this.maxDate = null;
  144 + } else if (Array.isArray(newVal)) {
  145 + this.minDate = newVal[0] ? toDate(newVal[0]) : null;
  146 + this.maxDate = newVal[1] ? toDate(newVal[1]) : null;
  147 + if (this.minDate) this.date = new Date(this.minDate);
  148 +// this.handleConfirm(true); // todo 稍后测试
  149 + }
23 150 }
24 151 },
25   - methods: {}
  152 + methods: {
  153 + prevYear () {
  154 +
  155 + },
  156 + nextYear () {
  157 +
  158 + },
  159 + prevMonth () {
  160 +
  161 + },
  162 + nextMonth () {
  163 +
  164 + },
  165 + showYearPicker () {
  166 +
  167 + },
  168 + showMonthPicker () {
  169 +
  170 + },
  171 + handleDatePick () {
  172 +
  173 + },
  174 + handleConfirm(visible) {
  175 + this.$emit('on-pick', [this.minDate, this.maxDate], visible);
  176 + }
  177 + }
26 178 }
27 179 </script>
28 180 \ No newline at end of file
... ...
src/components/date-picker/panel/date.vue
1 1 <template>
2 2 <div :class="classes">
3   - <div :class="[prefixCls + '-sidebar']" v-if="shortcuts">
  3 + <div :class="[prefixCls + '-sidebar']" v-if="shortcuts.length">
4 4 <div
5 5 :class="[prefixCls + '-shortcut']"
6 6 v-for="shortcut in shortcuts"
... ... @@ -67,10 +67,13 @@
67 67 import MonthTable from '../base/month-table.vue';
68 68 import { formatDate, parseDate } from '../util';
69 69  
  70 + import Mixin from './mixin';
  71 +
70 72 const prefixCls = 'ivu-picker-panel';
71 73 const datePrefixCls = 'ivu-date-picker';
72 74  
73 75 export default {
  76 + mixins: [Mixin],
74 77 components: { Icon, DateTable, YearTable, MonthTable },
75 78 data () {
76 79 return {
... ... @@ -114,13 +117,9 @@
114 117 if (!newVal) return;
115 118 newVal = new Date(newVal);
116 119 if (!isNaN(newVal)) {
117   - // todo
118   -// if (typeof this.disabledDate === 'function' && this.disabledDate(new Date(newVal))) return;
119   -
120 120 this.date = newVal;
121 121 this.year = newVal.getFullYear();
122 122 this.month = newVal.getMonth();
123   -// this.$emit('on-pick', newVal, true);
124 123 }
125 124 }
126 125 },
... ... @@ -129,17 +128,6 @@
129 128 this.date = new Date();
130 129 this.$emit('on-pick', '');
131 130 },
132   - handleShortcutClick (shortcut) {
133   - if (shortcut.value) this.$emit('on-pick', shortcut.value());
134   - if (shortcut.onClick) shortcut.onClick(this);
135   - },
136   - iconBtnCls (direction, type = '') {
137   - return [
138   - `${prefixCls}-icon-btn`,
139   - `${datePrefixCls}-${direction}-btn`,
140   - `${datePrefixCls}-${direction}-btn-arrow${type}`,
141   - ]
142   - },
143 131 resetDate () {
144 132 this.date = new Date(this.date);
145 133 },
... ...
src/components/date-picker/panel/mixin.js 0 → 100644
  1 +const prefixCls = 'ivu-picker-panel';
  2 +const datePrefixCls = 'ivu-date-picker';
  3 +
  4 +export default {
  5 + methods: {
  6 + iconBtnCls (direction, type = '') {
  7 + return [
  8 + `${prefixCls}-icon-btn`,
  9 + `${datePrefixCls}-${direction}-btn`,
  10 + `${datePrefixCls}-${direction}-btn-arrow${type}`,
  11 + ]
  12 + },
  13 + handleShortcutClick (shortcut) {
  14 + if (shortcut.value) this.$emit('on-pick', shortcut.value());
  15 + if (shortcut.onClick) shortcut.onClick(this);
  16 + }
  17 + }
  18 +}
0 19 \ No newline at end of file
... ...
src/styles/components/date-picker.less
1 1 @date-picker-prefix-cls: ~"@{css-prefix}date-picker";
2 2 @picker-prefix-cls: ~"@{css-prefix}picker";
3 3  
  4 +@date-picker-cells-width: 196px;
  5 +
4 6 .@{date-picker-prefix-cls} {
5 7 position: relative;
6 8 .@{select-dropdown-prefix-cls} {
... ... @@ -10,7 +12,7 @@
10 12 max-height: none;
11 13 }
12 14 &-cells{
13   - width: 196px;
  15 + width: @date-picker-cells-width;
14 16 margin: 10px;
15 17 span{
16 18 display: inline-block;
... ... @@ -81,7 +83,27 @@
81 83 }
82 84 }
83 85 }
84   - &-selected,&-selected:hover {
  86 + &-range{
  87 + position: relative;
  88 + em{
  89 + position: relative;
  90 + z-index: 1;
  91 + }
  92 + &:before{
  93 + content: '';
  94 + display: block;
  95 + background: @date-picker-cell-hover-bg;
  96 + border-radius: 0;
  97 + border: 0;
  98 + position: absolute;
  99 + top: 2px;
  100 + bottom: 2px;
  101 + left: 0;
  102 + right: 0;
  103 + }
  104 + }
  105 + &-selected,&-selected:hover
  106 + {
85 107 em{
86 108 background: @primary-color;
87 109 color: #fff;
... ... @@ -93,7 +115,8 @@
93 115 color: @btn-disable-bg;
94 116 }
95 117 }
96   - &-today&-selected{
  118 + &-today&-selected
  119 + {
97 120 em{
98 121 &:after{
99 122 background: #fff;
... ... @@ -151,6 +174,17 @@
151 174 }
152 175 }
153 176 }
  177 +
  178 + &-with-range{
  179 + .@{picker-prefix-cls}-panel{
  180 + &-body{
  181 + min-width: (@date-picker-cells-width + 20) * 2;
  182 + }
  183 + &-content{
  184 + float: left;
  185 + }
  186 + }
  187 + }
154 188 }
155 189  
156 190 .@{picker-prefix-cls} {
... ...
test/routers/date.vue
1 1 <template>
2   - <div style="margin: 150px">
  2 + <div style="margin: 50px">
3 3 <br>
4 4 <row>
5 5 <i-col span="8">
... ... @@ -11,11 +11,16 @@
11 11 :options="options"
12 12 @on-change="change"
13 13 :format="format"
14   - :editable="false"
15 14 @on-open-change="change2"></date-picker>
16 15 </i-col>
17 16 <i-col span="8">
18   - <date-picker type="daterange" style="width:200px" placeholder="请选择日期" :value.sync="value2" :options="options2"></date-picker>
  17 + <date-picker
  18 + type="daterange"
  19 + style="width:200px"
  20 + placeholder="请选择日期"
  21 + :value.sync="value2"
  22 + align="right"
  23 + :options="options2"></date-picker>
19 24 </i-col>
20 25 </row>
21 26 </div>
... ... @@ -26,9 +31,42 @@
26 31 return {
27 32 // value: new Date(),
28 33 value: '2016-12-25',
29   - value2: '',
  34 + value2: ['2016-12-17', '2017-01-05'],
30 35 options2: {
31   -
  36 + shortcuts: [
  37 + {
  38 + text: '今天',
  39 + value () {
  40 +// return new Date();
  41 + return '1/2/19'
  42 + },
  43 + onClick (picker) {
  44 + console.log('点击了今天');
  45 + }
  46 + },
  47 + {
  48 + text: '昨天',
  49 + value () {
  50 + const date = new Date();
  51 + date.setTime(date.getTime() - 3600 * 1000 * 24);
  52 + return date;
  53 + },
  54 + onClick () {
  55 + console.log('点击了昨天');
  56 + }
  57 + },
  58 + {
  59 + text: '最近三个月',
  60 + value () {
  61 + const date = new Date();
  62 + date.setTime(date.getTime() - 3600 * 1000 * 24 * 7);
  63 + return date;
  64 + },
  65 + onClick () {
  66 + console.log('点击了一周前');
  67 + }
  68 + }
  69 + ]
32 70 },
33 71 options: {
34 72 disabledDate(time) {
... ...