2
0
mirror of https://github.com/tenrok/vue2-datepicker.git synced 2026-06-21 08:10:36 +03:00

feat: support custom format function

This commit is contained in:
mengxiong10
2019-01-29 22:30:45 +08:00
parent f5dc1338ce
commit c8015164f1
7 changed files with 66 additions and 82 deletions
+1 -1
View File
@@ -85,7 +85,7 @@ export default {
|------|--------------|-------|---------| |------|--------------|-------|---------|
| type | select date type | 'date' \| 'datetime' \| 'year' \| 'month' \| 'time' | 'date' | | type | select date type | 'date' \| 'datetime' \| 'year' \| 'month' \| 'time' | 'date' |
| range | if true, the type is daterange or datetimerange | `boolean` | false | | range | if true, the type is daterange or datetimerange | `boolean` | false |
| format | format the Date. The parsing tokens are similar to the moment.js | [token](https://github.com/taylorhakes/fecha#formatting-tokens) | 'YYYY-MM-DD' | | format | format the Date. The parsing tokens are similar to the moment.js | [token](https://github.com/taylorhakes/fecha#formatting-tokens) \| [`object`](https://github.com/mengxiong10/vue2-datepicker/issues/232#issuecomment-458558141) | 'YYYY-MM-DD' |
| value-type | type of binding value. If not specified, the binding value will be a Date object | [value-type](#value-type) | 'date' | | value-type | type of binding value. If not specified, the binding value will be a Date object | [value-type](#value-type) | 'date' |
| lang | Translation | [lang](#lang) | 'zh' | | lang | Translation | [lang](#lang) | 'zh' |
| clearable | if false, don't show the clear icon | `boolean` | true | | clearable | if false, don't show the clear icon | `boolean` | true |
+1 -1
View File
@@ -85,7 +85,7 @@ export default {
|------|--------------|-------|---------| |------|--------------|-------|---------|
| type | 选择日期类型 | 'date' \| 'datetime' \| 'year' \| 'month' \| 'time' | 'date' | | type | 选择日期类型 | 'date' \| 'datetime' \| 'year' \| 'month' \| 'time' | 'date' |
| range | 如果是true, 显示日历范围选择 | `boolean` | false | | range | 如果是true, 显示日历范围选择 | `boolean` | false |
| format | 格式化显示日期, 值类似moment.js | [token](https://github.com/taylorhakes/fecha#formatting-tokens) | 'YYYY-MM-DD' | | format | 格式化显示日期, 值类似moment.js | [token](https://github.com/taylorhakes/fecha#formatting-tokens) \| [`object`](https://github.com/mengxiong10/vue2-datepicker/issues/232#issuecomment-458558141) | 'YYYY-MM-DD' |
| value-type | 设置绑定值的格式, 默认返回日期对象 | [value-type](#value-type) | 'date' | | value-type | 设置绑定值的格式, 默认返回日期对象 | [value-type](#value-type) | 'date' |
| lang | 选择语言或自定义 | [lang](#lang) | 'zh' | | lang | 选择语言或自定义 | [lang](#lang) | 'zh' |
| clearable | 如果设置false, 不显示清除图标 | `boolean` | true | | clearable | 如果设置false, 不显示清除图标 | `boolean` | true |
+53 -21
View File
@@ -110,8 +110,8 @@
<script> <script>
import fecha from 'fecha' import fecha from 'fecha'
import clickoutside from '@/directives/clickoutside' import clickoutside from '@/directives/clickoutside'
import { isValidDate, isValidRange, isDateObejct, isPlainObject, formatDate, parseDate, throttle } from '@/utils/index' import { isValidDate, isValidRangeDate, isDateObejct, isPlainObject, formatDate, parseDate, throttle } from '@/utils/index'
import { transformDate, transformDateRange } from '@/utils/transform' import { transformDate } from '@/utils/transform'
import CalendarPanel from './calendar.vue' import CalendarPanel from './calendar.vue'
import locale from '@/mixins/locale' import locale from '@/mixins/locale'
import Languages from '@/locale/languages' import Languages from '@/locale/languages'
@@ -141,7 +141,7 @@ export default {
default: 'zh' default: 'zh'
}, },
format: { format: {
type: String, type: [String, Object],
default: 'YYYY-MM-DD' default: 'YYYY-MM-DD'
}, },
dateFormat: { dateFormat: {
@@ -227,12 +227,17 @@ export default {
}, },
computed: { computed: {
transform () { transform () {
const obj = this.range ? transformDateRange : transformDate
const type = this.valueType const type = this.valueType
if (isPlainObject(type)) { if (isPlainObject(type)) {
return { ...obj.date, ...type } return { ...transformDate.date, ...type }
} }
return obj[type] || obj.date if (type === 'format') {
return {
value2date: this.parse.bind(this),
date2value: this.stringify.bind(this)
}
}
return transformDate[type] || transformDate.date
}, },
language () { language () {
if (isPlainObject(this.lang)) { if (isPlainObject(this.lang)) {
@@ -250,12 +255,14 @@ export default {
if (this.userInput !== null) { if (this.userInput !== null) {
return this.userInput return this.userInput
} }
const date = this.transform.value2date(this.value, this.format) const { value2date } = this.transform
if (!this.range) { if (!this.range) {
return date ? this.stringify(date) : '' return this.isValidValue(this.value)
? this.stringify(value2date(this.value))
: ''
} }
return Array.isArray(date) && date[0] && date[1] return this.isValidRangeValue(this.value)
? `${this.stringify(date[0])} ${this.rangeSeparator} ${this.stringify(date[1])}` ? `${this.stringify(value2date(this.value[0]))} ${this.rangeSeparator} ${this.stringify(value2date(this.value[1]))}`
: '' : ''
}, },
computedWidth () { computedWidth () {
@@ -265,7 +272,7 @@ export default {
return this.width return this.width
}, },
showClearIcon () { showClearIcon () {
return !this.disabled && this.clearable && (this.range ? isValidRange(this.value) : isValidDate(this.value)) return !this.disabled && this.clearable && (this.range ? this.isValidRangeValue(this.value) : this.isValidValue(this.value))
}, },
innerType () { innerType () {
return String(this.type).toLowerCase() return String(this.type).toLowerCase()
@@ -314,6 +321,9 @@ export default {
if (this.dateFormat) { if (this.dateFormat) {
return this.dateFormat return this.dateFormat
} }
if (typeof this.format !== 'string') {
return 'YYYY-MM-DD'
}
if (this.innerType === 'date') { if (this.innerType === 'date') {
return this.format return this.format
} }
@@ -348,11 +358,24 @@ export default {
this.handleValueChange(this.value) this.handleValueChange(this.value)
this.displayPopup() this.displayPopup()
}, },
stringify (date, format) { stringify (date) {
return formatDate(date, format || this.format) return (isPlainObject(this.format) && typeof this.format.stringify === 'function')
? this.format.stringify(date)
: formatDate(date, this.format)
}, },
parseDate (value, format) { parse (value) {
return parseDate(value, format || this.format) return (isPlainObject(this.format) && typeof this.format.parse === 'function')
? this.format.parse(value)
: parseDate(value, this.format)
},
isValidValue (value) {
const { value2date } = this.transform
return isValidDate(value2date(value))
},
isValidRangeValue (value) {
const { value2date } = this.transform
return Array.isArray(value) && value.length === 2 && this.isValidValue(value[0]) &&
this.isValidValue(value[1]) && (value2date(value[1]).getTime() >= value2date(value[0]).getTime())
}, },
dateEqual (a, b) { dateEqual (a, b) {
return isDateObejct(a) && isDateObejct(b) && a.getTime() === b.getTime() return isDateObejct(a) && isDateObejct(b) && a.getTime() === b.getTime()
@@ -374,7 +397,7 @@ export default {
this.$emit('clear') this.$emit('clear')
}, },
confirmDate () { confirmDate () {
const valid = this.range ? isValidRange(this.currentValue) : isValidDate(this.currentValue) const valid = this.range ? isValidRangeDate(this.currentValue) : isValidDate(this.currentValue)
if (valid) { if (valid) {
this.updateDate(true) this.updateDate(true)
} }
@@ -394,10 +417,19 @@ export default {
return true return true
}, },
emitDate (eventName) { emitDate (eventName) {
this.$emit(eventName, this.transform.date2value(this.currentValue, this.format)) const { date2value } = this.transform
const value = this.range
? this.currentValue.map(date2value)
: date2value(this.currentValue)
this.$emit(eventName, value)
}, },
handleValueChange (value) { handleValueChange (value) {
this.currentValue = this.transform.value2date(value, this.format) const { value2date } = this.transform
if (this.range) {
this.currentValue = this.isValidRangeValue(value) ? value.map(value2date) : [null, null]
} else {
this.currentValue = this.isValidValue(value) ? value2date(value) : null
}
}, },
selectDate (date) { selectDate (date) {
this.currentValue = date this.currentValue = date
@@ -497,8 +529,8 @@ export default {
if (this.range) { if (this.range) {
const range = value.split(` ${this.rangeSeparator} `) const range = value.split(` ${this.rangeSeparator} `)
if (range.length === 2) { if (range.length === 2) {
const start = this.parseDate(range[0], this.format) const start = this.parse(range[0])
const end = this.parseDate(range[1], this.format) const end = this.parse(range[1])
if (start && end && !checkDate(start, null, end) && !checkDate(end, start, null)) { if (start && end && !checkDate(start, null, end) && !checkDate(end, start, null)) {
this.currentValue = [start, end] this.currentValue = [start, end]
this.updateDate(true) this.updateDate(true)
@@ -507,7 +539,7 @@ export default {
} }
} }
} else { } else {
const date = this.parseDate(value, this.format) const date = this.parse(value)
if (date && !checkDate(date, null, null)) { if (date && !checkDate(date, null, null)) {
this.currentValue = date this.currentValue = date
this.updateDate(true) this.updateDate(true)
+1 -1
View File
@@ -15,7 +15,7 @@ export function isValidDate (date) {
return !isNaN(new Date(date).getTime()) return !isNaN(new Date(date).getTime())
} }
export function isValidRange (date) { export function isValidRangeDate (date) {
return ( return (
Array.isArray(date) && Array.isArray(date) &&
date.length === 2 && date.length === 2 &&
+2 -30
View File
@@ -1,4 +1,4 @@
import { isValidDate, isValidRange, parseDate, formatDate } from './index' import { isValidDate } from './index'
export const transformDate = { export const transformDate = {
date: { date: {
@@ -7,34 +7,6 @@ export const transformDate = {
}, },
timestamp: { timestamp: {
value2date: (value) => isValidDate(value) ? new Date(value) : null, value2date: (value) => isValidDate(value) ? new Date(value) : null,
date2value: (date) => isValidDate(date) ? new Date(date).getTime() : null date2value: (date) => date && new Date(date).getTime()
},
format: {
value2date: parseDate,
date2value: (date, format) => isValidDate(date) ? formatDate(date, format) : null
}
}
export const transformDateRange = {
date: {
value2date: (value) => isValidRange(value) ? [new Date(value[0]), new Date(value[1])] : [null, null],
date2value: (date) => date
},
timestamp: {
value2date: (value) => isValidRange(value) ? [new Date(value[0]), new Date(value[1])] : [null, null],
date2value: (date) => date.map(transformDate.timestamp.date2value)
},
format: {
value2date: (value, format) => {
if (Array.isArray(value) && value.length === 2) {
const value0 = parseDate(value[0], format)
const value1 = parseDate(value[1], format)
if (value0 && value1 && value1 >= value0) {
return [value0, value1]
}
}
return [null, null]
},
date2value: (date, format) => date.map(v => transformDate.format.date2value(v, format))
} }
} }
+1 -10
View File
@@ -5,7 +5,7 @@ import CalendarPanel from '../src/calendar.vue'
import DatePanel from '../src/panel/date' import DatePanel from '../src/panel/date'
import TimePanel from '../src/panel/time' import TimePanel from '../src/panel/time'
import YearPanel from '../src/panel/year' import YearPanel from '../src/panel/year'
import { transformDate, transformDateRange } from '../src/utils/transform' import { transformDate } from '../src/utils/transform'
let wrapper let wrapper
@@ -24,15 +24,6 @@ describe('datepicker', () => {
expect(vm.transform).toBe(transformDate.date) expect(vm.transform).toBe(transformDate.date)
wrapper.setProps({ valueType: 'timestamp' }) wrapper.setProps({ valueType: 'timestamp' })
expect(vm.transform).toBe(transformDate.timestamp) expect(vm.transform).toBe(transformDate.timestamp)
wrapper.setProps({ valueType: 'format' })
expect(vm.transform).toBe(transformDate.format)
wrapper.setProps({ valueType: 'date', range: true })
expect(vm.transform).toBe(transformDateRange.date)
wrapper.setProps({ valueType: 'timestamp' })
expect(vm.transform).toBe(transformDateRange.timestamp)
wrapper.setProps({ valueType: 'format' })
expect(vm.transform).toBe(transformDateRange.format)
const fn = (date) => date const fn = (date) => date
wrapper.setProps({ valueType: { wrapper.setProps({ valueType: {
+7 -18
View File
@@ -1,29 +1,18 @@
import { transformDate, transformDateRange } from '../src/utils/transform' import { transformDate } from '../src/utils/transform'
const time = new Date(2019, 1, 3) const time = new Date(2019, 1, 3)
const timestamp = time.getTime() const timestamp = time.getTime()
const format = 'MM-DD-YYYY'
const text = '02-03-2019'
const testfn = ({ type, value, date, err = null, range = false }) => it(`${type}}`, () => { const testfn = ({ type, value, date, err = null }) => it(`${type}}`, () => {
const obj = range ? transformDateRange : transformDate const obj = transformDate
const typeObj = obj[type] const typeObj = obj[type]
expect(typeObj.value2date(err, format)).toEqual(err) expect(typeObj.value2date(err)).toEqual(err)
expect(typeObj.value2date(value, format)).toEqual(date) expect(typeObj.value2date(value)).toEqual(date)
expect(typeObj.date2value(err, format)).toEqual(err) expect(typeObj.date2value(err)).toEqual(err)
expect(typeObj.date2value(date, format)).toEqual(value) expect(typeObj.date2value(date)).toEqual(value)
}) })
describe('transformDate', () => { describe('transformDate', () => {
testfn({ type: 'date', value: time, date: time }) testfn({ type: 'date', value: time, date: time })
testfn({ type: 'format', value: text, date: time })
testfn({ type: 'timestamp', value: timestamp, date: time }) testfn({ type: 'timestamp', value: timestamp, date: time })
}) })
describe('transformDateRange', () => {
const err = [null, null]
const date = [time, time]
testfn({ type: 'date', value: [time, time], date, err, range: true })
testfn({ type: 'format', value: [text, text], date, err, range: true })
testfn({ type: 'timestamp', value: [timestamp, timestamp], date, err, range: true })
})