DatePicker: optimize code, fix #12980, follow up #8156 (#13374)

* date-table: simplify implementation, fix #12980

* date-table: remove rangeState's row and column

* date-table: fix disabled cell highlight

this is a regression introduced in pr #8156, which allows disabled date to be
highlighted.

Also simplifies handleClick's implementation to avoid DOM operations.
pull/13398/head
Jiewei Qian 2018-11-12 22:19:58 +11:00 committed by hetech
parent 61f2b8afae
commit 9738054dd4
1 changed files with 60 additions and 122 deletions

View File

@ -32,16 +32,19 @@
</template> </template>
<script> <script>
import { getFirstDayOfMonth, getDayCountOfMonth, getWeekNumber, getStartDateOfMonth, nextDate, isDate } from '../util'; import { getFirstDayOfMonth, getDayCountOfMonth, getWeekNumber, getStartDateOfMonth, nextDate, isDate, clearTime as _clearTime} from '../util';
import { hasClass } from 'element-ui/src/utils/dom';
import Locale from 'element-ui/src/mixins/locale'; import Locale from 'element-ui/src/mixins/locale';
import { arrayFindIndex, arrayFind, coerceTruthyValueToArray } from 'element-ui/src/utils/util'; import { arrayFindIndex, arrayFind, coerceTruthyValueToArray } from 'element-ui/src/utils/util';
const WEEKS = ['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat']; const WEEKS = ['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat'];
const clearHours = function(time) { const getDateTimestamp = function(time) {
const cloneDate = new Date(time); if (typeof time === 'number' || typeof time === 'string') {
cloneDate.setHours(0, 0, 0, 0); return _clearTime(new Date(time)).getTime();
return cloneDate.getTime(); } else if (time instanceof Date) {
return _clearTime(time).getTime();
} else {
return NaN;
}
}; };
// remove the first element that satisfies `pred` from arr // remove the first element that satisfies `pred` from arr
@ -92,9 +95,7 @@
default() { default() {
return { return {
endDate: null, endDate: null,
selecting: false, selecting: false
row: null,
column: null
}; };
} }
} }
@ -141,7 +142,7 @@
const startDate = this.startDate; const startDate = this.startDate;
const disabledDate = this.disabledDate; const disabledDate = this.disabledDate;
const selectedDate = this.selectionMode === 'dates' ? coerceTruthyValueToArray(this.value) : []; const selectedDate = this.selectionMode === 'dates' ? coerceTruthyValueToArray(this.value) : [];
const now = clearHours(new Date()); const now = getDateTimestamp(new Date());
for (let i = 0; i < 6; i++) { for (let i = 0; i < 6; i++) {
const row = rows[i]; const row = rows[i];
@ -162,9 +163,9 @@
const index = i * 7 + j; const index = i * 7 + j;
const time = nextDate(startDate, index - offset).getTime(); const time = nextDate(startDate, index - offset).getTime();
cell.inRange = time >= clearHours(this.minDate) && time <= clearHours(this.maxDate); cell.inRange = time >= getDateTimestamp(this.minDate) && time <= getDateTimestamp(this.maxDate);
cell.start = this.minDate && time === clearHours(this.minDate); cell.start = this.minDate && time === getDateTimestamp(this.minDate);
cell.end = this.maxDate && time === clearHours(this.maxDate); cell.end = this.maxDate && time === getDateTimestamp(this.maxDate);
const isToday = time === now; const isToday = time === now;
if (isToday) { if (isToday) {
@ -220,32 +221,27 @@
watch: { watch: {
'rangeState.endDate'(newVal) { 'rangeState.endDate'(newVal) {
this.markRange(newVal); this.markRange(this.minDate, newVal);
}, },
minDate(newVal, oldVal) { minDate(newVal, oldVal) {
if (newVal && !oldVal) { if (getDateTimestamp(newVal) !== getDateTimestamp(oldVal)) {
this.rangeState.selecting = true; this.markRange(this.minDate, this.maxDate);
this.markRange(newVal);
} else if (!newVal) {
this.rangeState.selecting = false;
this.markRange(newVal);
} else {
this.markRange();
} }
}, },
maxDate(newVal, oldVal) { maxDate(newVal, oldVal) {
if (newVal && !oldVal) { if (getDateTimestamp(newVal) !== getDateTimestamp(oldVal)) {
this.rangeState.selecting = false; this.markRange(this.minDate, this.maxDate);
this.markRange(newVal);
} }
} }
}, },
data() { data() {
return { return {
tableRows: [ [], [], [], [], [], [] ] tableRows: [ [], [], [], [], [], [] ],
lastRow: null,
lastColumn: null
}; };
}, },
@ -329,14 +325,13 @@
return year === valueYear && getWeekNumber(newDate) === getWeekNumber(this.value); return year === valueYear && getWeekNumber(newDate) === getWeekNumber(this.value);
}, },
markRange(maxDate) { markRange(minDate, maxDate) {
const startDate = this.startDate; minDate = getDateTimestamp(minDate);
if (!maxDate) { maxDate = getDateTimestamp(maxDate) || minDate;
maxDate = this.maxDate; [minDate, maxDate] = [Math.min(minDate, maxDate), Math.max(minDate, maxDate)];
}
const startDate = this.startDate;
const rows = this.rows; const rows = this.rows;
const minDate = this.minDate;
for (let i = 0, k = rows.length; i < k; i++) { for (let i = 0, k = rows.length; i < k; i++) {
const row = rows[i]; const row = rows[i];
for (let j = 0, l = row.length; j < l; j++) { for (let j = 0, l = row.length; j < l; j++) {
@ -346,15 +341,9 @@
const index = i * 7 + j + (this.showWeekNumber ? -1 : 0); const index = i * 7 + j + (this.showWeekNumber ? -1 : 0);
const time = nextDate(startDate, index - this.offsetDay).getTime(); const time = nextDate(startDate, index - this.offsetDay).getTime();
if (maxDate && maxDate < minDate) { cell.inRange = minDate && time >= minDate && time <= maxDate;
cell.inRange = minDate && time >= clearHours(maxDate) && time <= clearHours(minDate); cell.start = minDate && time === minDate;
cell.start = maxDate && time === clearHours(maxDate.getTime()); cell.end = maxDate && time === maxDate;
cell.end = minDate && time === clearHours(minDate.getTime());
} else {
cell.inRange = minDate && time >= clearHours(minDate) && time <= clearHours(maxDate);
cell.start = minDate && time === clearHours(minDate.getTime());
cell.end = maxDate && time === clearHours(maxDate.getTime());
}
} }
} }
}, },
@ -362,12 +351,6 @@
handleMouseMove(event) { handleMouseMove(event) {
if (!this.rangeState.selecting) return; if (!this.rangeState.selecting) return;
this.$emit('changerange', {
minDate: this.minDate,
maxDate: this.maxDate,
rangeState: this.rangeState
});
let target = event.target; let target = event.target;
if (target.tagName === 'SPAN') { if (target.tagName === 'SPAN') {
target = target.parentNode.parentNode; target = target.parentNode.parentNode;
@ -377,15 +360,25 @@
} }
if (target.tagName !== 'TD') return; if (target.tagName !== 'TD') return;
const column = target.cellIndex;
const row = target.parentNode.rowIndex - 1; const row = target.parentNode.rowIndex - 1;
const { row: oldRow, column: oldColumn } = this.rangeState; const column = target.cellIndex;
if (oldRow !== row || oldColumn !== column) { // can not select disabled date
this.rangeState.row = row; if (this.rows[row][column].disabled) return;
this.rangeState.column = column;
this.rangeState.endDate = this.getDateOfCell(row, column); // only update rangeState when mouse moves to a new cell
// this avoids frequent Date object creation and improves performance
if (row !== this.lastRow || column !== this.lastColumn) {
this.lastRow = row;
this.lastColumn = column;
this.$emit('changerange', {
minDate: this.minDate,
maxDate: this.maxDate,
rangeState: {
selecting: true,
endDate: this.getDateOfCell(row, column)
}
});
} }
}, },
@ -399,86 +392,31 @@
} }
if (target.tagName !== 'TD') return; if (target.tagName !== 'TD') return;
if (hasClass(target, 'disabled') || hasClass(target, 'week')) return;
const selectionMode = this.selectionMode; const row = target.parentNode.rowIndex - 1;
const column = this.selectionMode === 'week' ? 1 : target.cellIndex;
const cell = this.rows[row][column];
if (selectionMode === 'week') { if (cell.disabled || cell.type === 'week') return;
target = target.parentNode.cells[1];
}
let year = Number(this.year); const newDate = this.getDateOfCell(row, column);
let month = Number(this.month);
const cellIndex = target.cellIndex;
const rowIndex = target.parentNode.rowIndex;
const cell = this.rows[rowIndex - 1][cellIndex];
const text = cell.text;
const className = target.className;
const newDate = new Date(year, month, 1);
if (className.indexOf('prev') !== -1) {
if (month === 0) {
year = year - 1;
month = 11;
} else {
month = month - 1;
}
newDate.setFullYear(year);
newDate.setMonth(month);
} else if (className.indexOf('next') !== -1) {
if (month === 11) {
year = year + 1;
month = 0;
} else {
month = month + 1;
}
newDate.setFullYear(year);
newDate.setMonth(month);
}
newDate.setDate(parseInt(text, 10));
if (this.selectionMode === 'range') { if (this.selectionMode === 'range') {
if (this.minDate && this.maxDate) { if (!this.rangeState.selecting) {
const minDate = new Date(newDate.getTime()); this.$emit('pick', {minDate: newDate, maxDate: null});
const maxDate = null;
this.$emit('pick', { minDate, maxDate }, false);
this.rangeState.selecting = true; this.rangeState.selecting = true;
this.markRange(this.minDate); } else {
this.$nextTick(() => {
this.handleMouseMove(event);
});
} else if (this.minDate && !this.maxDate) {
if (newDate >= this.minDate) { if (newDate >= this.minDate) {
const maxDate = new Date(newDate.getTime()); this.$emit('pick', {minDate: this.minDate, maxDate: newDate});
this.rangeState.selecting = false;
this.$emit('pick', {
minDate: this.minDate,
maxDate
});
} else { } else {
const minDate = new Date(newDate.getTime()); this.$emit('pick', {minDate: newDate, maxDate: this.minDate});
this.rangeState.selecting = false;
this.$emit('pick', { minDate, maxDate: this.minDate });
} }
} else if (!this.minDate) { this.rangeState.selecting = false;
const minDate = new Date(newDate.getTime());
this.$emit('pick', { minDate, maxDate: this.maxDate }, false);
this.rangeState.selecting = true;
this.markRange(this.minDate);
} }
} else if (selectionMode === 'day') { } else if (this.selectionMode === 'day') {
this.$emit('pick', newDate); this.$emit('pick', newDate);
} else if (selectionMode === 'week') { } else if (this.selectionMode === 'week') {
const weekNumber = getWeekNumber(newDate); const weekNumber = getWeekNumber(newDate);
const value = newDate.getFullYear() + 'w' + weekNumber; const value = newDate.getFullYear() + 'w' + weekNumber;
this.$emit('pick', { this.$emit('pick', {
year: newDate.getFullYear(), year: newDate.getFullYear(),
@ -486,7 +424,7 @@
value: value, value: value,
date: newDate date: newDate
}); });
} else if (selectionMode === 'dates') { } else if (this.selectionMode === 'dates') {
const value = this.value || []; const value = this.value || [];
const newValue = cell.selected const newValue = cell.selected
? removeFromArray(value, date => date.getTime() === newDate.getTime()) ? removeFromArray(value, date => date.getTime() === newDate.getTime())