Commit 3cf7cfd1de4022361d8e0bae254f9f6e23cc6403

Authored by 梁灏
1 parent e0cd7f90

update DatePicker

update DatePicker
src/components/date-picker/base/date-table.vue
@@ -36,9 +36,7 @@ @@ -36,9 +36,7 @@
36 default () { 36 default () {
37 return { 37 return {
38 endDate: null, 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,6 +62,8 @@
64 day = (day === 0 ? 7 : day); 62 day = (day === 0 ? 7 : day);
65 const today = clearHours(new Date()); // timestamp of today 63 const today = clearHours(new Date()); // timestamp of today
66 const selectDay = clearHours(new Date(this.value)); // timestamp of selected day 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 const dateCountOfMonth = getDayCountOfMonth(date.getFullYear(), date.getMonth()); 68 const dateCountOfMonth = getDayCountOfMonth(date.getFullYear(), date.getMonth());
69 const dateCountOfLastMonth = getDayCountOfMonth(date.getFullYear(), (date.getMonth() === 0 ? 11 : date.getMonth() - 1)); 69 const dateCountOfLastMonth = getDayCountOfMonth(date.getFullYear(), (date.getMonth() === 0 ? 11 : date.getMonth() - 1));
@@ -75,7 +75,10 @@ @@ -75,7 +75,10 @@
75 text: '', 75 text: '',
76 type: '', 76 type: '',
77 selected: false, 77 selected: false,
78 - disabled: false 78 + disabled: false,
  79 + range: false,
  80 + start: false,
  81 + end: false
79 }; 82 };
80 if (day !== 7) { 83 if (day !== 7) {
81 for (let i = 0; i < day; i++) { 84 for (let i = 0; i < day; i++) {
@@ -102,6 +105,10 @@ @@ -102,6 +105,10 @@
102 cell.text = i; 105 cell.text = i;
103 cell.selected = time === selectDay; 106 cell.selected = time === selectDay;
104 cell.disabled = typeof disabledDate === 'function' && disabledDate(new Date(time)); 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 cells.push(cell); 112 cells.push(cell);
106 } 113 }
107 114
@@ -156,6 +163,30 @@ @@ -156,6 +163,30 @@
156 163
157 if (this.selectionMode === 'range') { 164 if (this.selectionMode === 'range') {
158 // todo 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 } else { 190 } else {
160 this.$emit('on-pick', newDate); 191 this.$emit('on-pick', newDate);
161 } 192 }
@@ -164,15 +195,39 @@ @@ -164,15 +195,39 @@
164 handleMouseMove () { 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 getCellCls (cell) { 221 getCellCls (cell) {
168 return [ 222 return [
169 `${prefixCls}-cell`, 223 `${prefixCls}-cell`,
170 { 224 {
171 - [`${prefixCls}-cell-selected`]: cell.selected, 225 + [`${prefixCls}-cell-selected`]: cell.selected || cell.start || cell.end,
172 [`${prefixCls}-cell-disabled`]: cell.disabled, 226 [`${prefixCls}-cell-disabled`]: cell.disabled,
173 [`${prefixCls}-cell-today`]: cell.type === 'today', 227 [`${prefixCls}-cell-today`]: cell.type === 'today',
174 [`${prefixCls}-cell-prev-month`]: cell.type === 'prev-month', 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 <template> 1 <template>
2 <div :class="classes"> 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 </div> 69 </div>
5 </template> 70 </template>
6 <script> 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 const prefixCls = 'ivu-picker-panel'; 78 const prefixCls = 'ivu-picker-panel';
8 const datePrefixCls = 'ivu-date-picker'; 79 const datePrefixCls = 'ivu-date-picker';
9 80
10 export default { 81 export default {
11 - props: {}, 82 + mixins: [Mixin],
  83 + components: { Icon, DateTable },
12 data () { 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 computed: { 103 computed: {
16 classes () { 104 classes () {
17 return [ 105 return [
18 `${prefixCls}-body-wrapper`, 106 `${prefixCls}-body-wrapper`,
  107 + `${datePrefixCls}-with-range`,
19 { 108 {
20 [`${prefixCls}-with-sidebar`]: this.shortcuts.length 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 </script> 179 </script>
28 \ No newline at end of file 180 \ No newline at end of file
src/components/date-picker/panel/date.vue
1 <template> 1 <template>
2 <div :class="classes"> 2 <div :class="classes">
3 - <div :class="[prefixCls + '-sidebar']" v-if="shortcuts"> 3 + <div :class="[prefixCls + '-sidebar']" v-if="shortcuts.length">
4 <div 4 <div
5 :class="[prefixCls + '-shortcut']" 5 :class="[prefixCls + '-shortcut']"
6 v-for="shortcut in shortcuts" 6 v-for="shortcut in shortcuts"
@@ -67,10 +67,13 @@ @@ -67,10 +67,13 @@
67 import MonthTable from '../base/month-table.vue'; 67 import MonthTable from '../base/month-table.vue';
68 import { formatDate, parseDate } from '../util'; 68 import { formatDate, parseDate } from '../util';
69 69
  70 + import Mixin from './mixin';
  71 +
70 const prefixCls = 'ivu-picker-panel'; 72 const prefixCls = 'ivu-picker-panel';
71 const datePrefixCls = 'ivu-date-picker'; 73 const datePrefixCls = 'ivu-date-picker';
72 74
73 export default { 75 export default {
  76 + mixins: [Mixin],
74 components: { Icon, DateTable, YearTable, MonthTable }, 77 components: { Icon, DateTable, YearTable, MonthTable },
75 data () { 78 data () {
76 return { 79 return {
@@ -114,13 +117,9 @@ @@ -114,13 +117,9 @@
114 if (!newVal) return; 117 if (!newVal) return;
115 newVal = new Date(newVal); 118 newVal = new Date(newVal);
116 if (!isNaN(newVal)) { 119 if (!isNaN(newVal)) {
117 - // todo  
118 -// if (typeof this.disabledDate === 'function' && this.disabledDate(new Date(newVal))) return;  
119 -  
120 this.date = newVal; 120 this.date = newVal;
121 this.year = newVal.getFullYear(); 121 this.year = newVal.getFullYear();
122 this.month = newVal.getMonth(); 122 this.month = newVal.getMonth();
123 -// this.$emit('on-pick', newVal, true);  
124 } 123 }
125 } 124 }
126 }, 125 },
@@ -129,17 +128,6 @@ @@ -129,17 +128,6 @@
129 this.date = new Date(); 128 this.date = new Date();
130 this.$emit('on-pick', ''); 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 resetDate () { 131 resetDate () {
144 this.date = new Date(this.date); 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 \ No newline at end of file 19 \ No newline at end of file
src/styles/components/date-picker.less
1 @date-picker-prefix-cls: ~"@{css-prefix}date-picker"; 1 @date-picker-prefix-cls: ~"@{css-prefix}date-picker";
2 @picker-prefix-cls: ~"@{css-prefix}picker"; 2 @picker-prefix-cls: ~"@{css-prefix}picker";
3 3
  4 +@date-picker-cells-width: 196px;
  5 +
4 .@{date-picker-prefix-cls} { 6 .@{date-picker-prefix-cls} {
5 position: relative; 7 position: relative;
6 .@{select-dropdown-prefix-cls} { 8 .@{select-dropdown-prefix-cls} {
@@ -10,7 +12,7 @@ @@ -10,7 +12,7 @@
10 max-height: none; 12 max-height: none;
11 } 13 }
12 &-cells{ 14 &-cells{
13 - width: 196px; 15 + width: @date-picker-cells-width;
14 margin: 10px; 16 margin: 10px;
15 span{ 17 span{
16 display: inline-block; 18 display: inline-block;
@@ -81,7 +83,27 @@ @@ -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 em{ 107 em{
86 background: @primary-color; 108 background: @primary-color;
87 color: #fff; 109 color: #fff;
@@ -93,7 +115,8 @@ @@ -93,7 +115,8 @@
93 color: @btn-disable-bg; 115 color: @btn-disable-bg;
94 } 116 }
95 } 117 }
96 - &-today&-selected{ 118 + &-today&-selected
  119 + {
97 em{ 120 em{
98 &:after{ 121 &:after{
99 background: #fff; 122 background: #fff;
@@ -151,6 +174,17 @@ @@ -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 .@{picker-prefix-cls} { 190 .@{picker-prefix-cls} {
test/routers/date.vue
1 <template> 1 <template>
2 - <div style="margin: 150px"> 2 + <div style="margin: 50px">
3 <br> 3 <br>
4 <row> 4 <row>
5 <i-col span="8"> 5 <i-col span="8">
@@ -11,11 +11,16 @@ @@ -11,11 +11,16 @@
11 :options="options" 11 :options="options"
12 @on-change="change" 12 @on-change="change"
13 :format="format" 13 :format="format"
14 - :editable="false"  
15 @on-open-change="change2"></date-picker> 14 @on-open-change="change2"></date-picker>
16 </i-col> 15 </i-col>
17 <i-col span="8"> 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 </i-col> 24 </i-col>
20 </row> 25 </row>
21 </div> 26 </div>
@@ -26,9 +31,42 @@ @@ -26,9 +31,42 @@
26 return { 31 return {
27 // value: new Date(), 32 // value: new Date(),
28 value: '2016-12-25', 33 value: '2016-12-25',
29 - value2: '', 34 + value2: ['2016-12-17', '2017-01-05'],
30 options2: { 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 options: { 71 options: {
34 disabledDate(time) { 72 disabledDate(time) {