Skip to content

Commit c801516

Browse files
committed
feat: support custom format function
1 parent f5dc133 commit c801516

File tree

7 files changed

+66
-82
lines changed

7 files changed

+66
-82
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ export default {
8585
|------|--------------|-------|---------|
8686
| type | select date type | 'date' \| 'datetime' \| 'year' \| 'month' \| 'time' | 'date' |
8787
| range | if true, the type is daterange or datetimerange | `boolean` | false |
88-
| format | format the Date. The parsing tokens are similar to the moment.js | [token](https://github.com/taylorhakes/fecha#formatting-tokens) | 'YYYY-MM-DD' |
88+
| 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' |
8989
| value-type | type of binding value. If not specified, the binding value will be a Date object | [value-type](#value-type) | 'date' |
9090
| lang | Translation | [lang](#lang) | 'zh' |
9191
| clearable | if false, don't show the clear icon | `boolean` | true |

README.zh-CN.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ export default {
8585
|------|--------------|-------|---------|
8686
| type | 选择日期类型 | 'date' \| 'datetime' \| 'year' \| 'month' \| 'time' | 'date' |
8787
| range | 如果是true, 显示日历范围选择 | `boolean` | false |
88-
| format | 格式化显示日期, 值类似moment.js | [token](https://github.com/taylorhakes/fecha#formatting-tokens) | 'YYYY-MM-DD' |
88+
| 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' |
8989
| value-type | 设置绑定值的格式, 默认返回日期对象 | [value-type](#value-type) | 'date' |
9090
| lang | 选择语言或自定义 | [lang](#lang) | 'zh' |
9191
| clearable | 如果设置false, 不显示清除图标 | `boolean` | true |

src/index.vue

Lines changed: 53 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -110,8 +110,8 @@
110110
<script>
111111
import fecha from 'fecha'
112112
import clickoutside from '@/directives/clickoutside'
113-
import { isValidDate, isValidRange, isDateObejct, isPlainObject, formatDate, parseDate, throttle } from '@/utils/index'
114-
import { transformDate, transformDateRange } from '@/utils/transform'
113+
import { isValidDate, isValidRangeDate, isDateObejct, isPlainObject, formatDate, parseDate, throttle } from '@/utils/index'
114+
import { transformDate } from '@/utils/transform'
115115
import CalendarPanel from './calendar.vue'
116116
import locale from '@/mixins/locale'
117117
import Languages from '@/locale/languages'
@@ -141,7 +141,7 @@ export default {
141141
default: 'zh'
142142
},
143143
format: {
144-
type: String,
144+
type: [String, Object],
145145
default: 'YYYY-MM-DD'
146146
},
147147
dateFormat: {
@@ -227,12 +227,17 @@ export default {
227227
},
228228
computed: {
229229
transform () {
230-
const obj = this.range ? transformDateRange : transformDate
231230
const type = this.valueType
232231
if (isPlainObject(type)) {
233-
return { ...obj.date, ...type }
232+
return { ...transformDate.date, ...type }
234233
}
235-
return obj[type] || obj.date
234+
if (type === 'format') {
235+
return {
236+
value2date: this.parse.bind(this),
237+
date2value: this.stringify.bind(this)
238+
}
239+
}
240+
return transformDate[type] || transformDate.date
236241
},
237242
language () {
238243
if (isPlainObject(this.lang)) {
@@ -250,12 +255,14 @@ export default {
250255
if (this.userInput !== null) {
251256
return this.userInput
252257
}
253-
const date = this.transform.value2date(this.value, this.format)
258+
const { value2date } = this.transform
254259
if (!this.range) {
255-
return date ? this.stringify(date) : ''
260+
return this.isValidValue(this.value)
261+
? this.stringify(value2date(this.value))
262+
: ''
256263
}
257-
return Array.isArray(date) && date[0] && date[1]
258-
? `${this.stringify(date[0])} ${this.rangeSeparator} ${this.stringify(date[1])}`
264+
return this.isValidRangeValue(this.value)
265+
? `${this.stringify(value2date(this.value[0]))} ${this.rangeSeparator} ${this.stringify(value2date(this.value[1]))}`
259266
: ''
260267
},
261268
computedWidth () {
@@ -265,7 +272,7 @@ export default {
265272
return this.width
266273
},
267274
showClearIcon () {
268-
return !this.disabled && this.clearable && (this.range ? isValidRange(this.value) : isValidDate(this.value))
275+
return !this.disabled && this.clearable && (this.range ? this.isValidRangeValue(this.value) : this.isValidValue(this.value))
269276
},
270277
innerType () {
271278
return String(this.type).toLowerCase()
@@ -314,6 +321,9 @@ export default {
314321
if (this.dateFormat) {
315322
return this.dateFormat
316323
}
324+
if (typeof this.format !== 'string') {
325+
return 'YYYY-MM-DD'
326+
}
317327
if (this.innerType === 'date') {
318328
return this.format
319329
}
@@ -348,11 +358,24 @@ export default {
348358
this.handleValueChange(this.value)
349359
this.displayPopup()
350360
},
351-
stringify (date, format) {
352-
return formatDate(date, format || this.format)
361+
stringify (date) {
362+
return (isPlainObject(this.format) && typeof this.format.stringify === 'function')
363+
? this.format.stringify(date)
364+
: formatDate(date, this.format)
353365
},
354-
parseDate (value, format) {
355-
return parseDate(value, format || this.format)
366+
parse (value) {
367+
return (isPlainObject(this.format) && typeof this.format.parse === 'function')
368+
? this.format.parse(value)
369+
: parseDate(value, this.format)
370+
},
371+
isValidValue (value) {
372+
const { value2date } = this.transform
373+
return isValidDate(value2date(value))
374+
},
375+
isValidRangeValue (value) {
376+
const { value2date } = this.transform
377+
return Array.isArray(value) && value.length === 2 && this.isValidValue(value[0]) &&
378+
this.isValidValue(value[1]) && (value2date(value[1]).getTime() >= value2date(value[0]).getTime())
356379
},
357380
dateEqual (a, b) {
358381
return isDateObejct(a) && isDateObejct(b) && a.getTime() === b.getTime()
@@ -374,7 +397,7 @@ export default {
374397
this.$emit('clear')
375398
},
376399
confirmDate () {
377-
const valid = this.range ? isValidRange(this.currentValue) : isValidDate(this.currentValue)
400+
const valid = this.range ? isValidRangeDate(this.currentValue) : isValidDate(this.currentValue)
378401
if (valid) {
379402
this.updateDate(true)
380403
}
@@ -394,10 +417,19 @@ export default {
394417
return true
395418
},
396419
emitDate (eventName) {
397-
this.$emit(eventName, this.transform.date2value(this.currentValue, this.format))
420+
const { date2value } = this.transform
421+
const value = this.range
422+
? this.currentValue.map(date2value)
423+
: date2value(this.currentValue)
424+
this.$emit(eventName, value)
398425
},
399426
handleValueChange (value) {
400-
this.currentValue = this.transform.value2date(value, this.format)
427+
const { value2date } = this.transform
428+
if (this.range) {
429+
this.currentValue = this.isValidRangeValue(value) ? value.map(value2date) : [null, null]
430+
} else {
431+
this.currentValue = this.isValidValue(value) ? value2date(value) : null
432+
}
401433
},
402434
selectDate (date) {
403435
this.currentValue = date
@@ -497,8 +529,8 @@ export default {
497529
if (this.range) {
498530
const range = value.split(` ${this.rangeSeparator} `)
499531
if (range.length === 2) {
500-
const start = this.parseDate(range[0], this.format)
501-
const end = this.parseDate(range[1], this.format)
532+
const start = this.parse(range[0])
533+
const end = this.parse(range[1])
502534
if (start && end && !checkDate(start, null, end) && !checkDate(end, start, null)) {
503535
this.currentValue = [start, end]
504536
this.updateDate(true)
@@ -507,7 +539,7 @@ export default {
507539
}
508540
}
509541
} else {
510-
const date = this.parseDate(value, this.format)
542+
const date = this.parse(value)
511543
if (date && !checkDate(date, null, null)) {
512544
this.currentValue = date
513545
this.updateDate(true)

src/utils/index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ export function isValidDate (date) {
1515
return !isNaN(new Date(date).getTime())
1616
}
1717

18-
export function isValidRange (date) {
18+
export function isValidRangeDate (date) {
1919
return (
2020
Array.isArray(date) &&
2121
date.length === 2 &&

src/utils/transform.js

Lines changed: 2 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { isValidDate, isValidRange, parseDate, formatDate } from './index'
1+
import { isValidDate } from './index'
22

33
export const transformDate = {
44
date: {
@@ -7,34 +7,6 @@ export const transformDate = {
77
},
88
timestamp: {
99
value2date: (value) => isValidDate(value) ? new Date(value) : null,
10-
date2value: (date) => isValidDate(date) ? new Date(date).getTime() : null
11-
},
12-
format: {
13-
value2date: parseDate,
14-
date2value: (date, format) => isValidDate(date) ? formatDate(date, format) : null
15-
}
16-
}
17-
18-
export const transformDateRange = {
19-
date: {
20-
value2date: (value) => isValidRange(value) ? [new Date(value[0]), new Date(value[1])] : [null, null],
21-
date2value: (date) => date
22-
},
23-
timestamp: {
24-
value2date: (value) => isValidRange(value) ? [new Date(value[0]), new Date(value[1])] : [null, null],
25-
date2value: (date) => date.map(transformDate.timestamp.date2value)
26-
},
27-
format: {
28-
value2date: (value, format) => {
29-
if (Array.isArray(value) && value.length === 2) {
30-
const value0 = parseDate(value[0], format)
31-
const value1 = parseDate(value[1], format)
32-
if (value0 && value1 && value1 >= value0) {
33-
return [value0, value1]
34-
}
35-
}
36-
return [null, null]
37-
},
38-
date2value: (date, format) => date.map(v => transformDate.format.date2value(v, format))
10+
date2value: (date) => date && new Date(date).getTime()
3911
}
4012
}

test/index.spec.js

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import CalendarPanel from '../src/calendar.vue'
55
import DatePanel from '../src/panel/date'
66
import TimePanel from '../src/panel/time'
77
import YearPanel from '../src/panel/year'
8-
import { transformDate, transformDateRange } from '../src/utils/transform'
8+
import { transformDate } from '../src/utils/transform'
99

1010
let wrapper
1111

@@ -24,15 +24,6 @@ describe('datepicker', () => {
2424
expect(vm.transform).toBe(transformDate.date)
2525
wrapper.setProps({ valueType: 'timestamp' })
2626
expect(vm.transform).toBe(transformDate.timestamp)
27-
wrapper.setProps({ valueType: 'format' })
28-
expect(vm.transform).toBe(transformDate.format)
29-
30-
wrapper.setProps({ valueType: 'date', range: true })
31-
expect(vm.transform).toBe(transformDateRange.date)
32-
wrapper.setProps({ valueType: 'timestamp' })
33-
expect(vm.transform).toBe(transformDateRange.timestamp)
34-
wrapper.setProps({ valueType: 'format' })
35-
expect(vm.transform).toBe(transformDateRange.format)
3627

3728
const fn = (date) => date
3829
wrapper.setProps({ valueType: {

test/transform.spec.js

Lines changed: 7 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,18 @@
1-
import { transformDate, transformDateRange } from '../src/utils/transform'
1+
import { transformDate } from '../src/utils/transform'
22

33
const time = new Date(2019, 1, 3)
44
const timestamp = time.getTime()
5-
const format = 'MM-DD-YYYY'
6-
const text = '02-03-2019'
75

8-
const testfn = ({ type, value, date, err = null, range = false }) => it(`${type}}`, () => {
9-
const obj = range ? transformDateRange : transformDate
6+
const testfn = ({ type, value, date, err = null }) => it(`${type}}`, () => {
7+
const obj = transformDate
108
const typeObj = obj[type]
11-
expect(typeObj.value2date(err, format)).toEqual(err)
12-
expect(typeObj.value2date(value, format)).toEqual(date)
13-
expect(typeObj.date2value(err, format)).toEqual(err)
14-
expect(typeObj.date2value(date, format)).toEqual(value)
9+
expect(typeObj.value2date(err)).toEqual(err)
10+
expect(typeObj.value2date(value)).toEqual(date)
11+
expect(typeObj.date2value(err)).toEqual(err)
12+
expect(typeObj.date2value(date)).toEqual(value)
1513
})
1614

1715
describe('transformDate', () => {
1816
testfn({ type: 'date', value: time, date: time })
19-
testfn({ type: 'format', value: text, date: time })
2017
testfn({ type: 'timestamp', value: timestamp, date: time })
2118
})
22-
23-
describe('transformDateRange', () => {
24-
const err = [null, null]
25-
const date = [time, time]
26-
testfn({ type: 'date', value: [time, time], date, err, range: true })
27-
testfn({ type: 'format', value: [text, text], date, err, range: true })
28-
testfn({ type: 'timestamp', value: [timestamp, timestamp], date, err, range: true })
29-
})

0 commit comments

Comments
 (0)