Skip to content

Commit

Permalink
feat: support custom format function
Browse files Browse the repository at this point in the history
  • Loading branch information
mengxiong10 committed Jan 29, 2019
1 parent f5dc133 commit c801516
Show file tree
Hide file tree
Showing 7 changed files with 66 additions and 82 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ export default {
|------|--------------|-------|---------|
| type | select date type | 'date' \| 'datetime' \| 'year' \| 'month' \| 'time' | 'date' |
| 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' |
| lang | Translation | [lang](#lang) | 'zh' |
| clearable | if false, don't show the clear icon | `boolean` | true |
Expand Down
2 changes: 1 addition & 1 deletion README.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ export default {
|------|--------------|-------|---------|
| type | 选择日期类型 | 'date' \| 'datetime' \| 'year' \| 'month' \| 'time' | 'date' |
| 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' |
| lang | 选择语言或自定义 | [lang](#lang) | 'zh' |
| clearable | 如果设置false, 不显示清除图标 | `boolean` | true |
Expand Down
74 changes: 53 additions & 21 deletions src/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -110,8 +110,8 @@
<script>
import fecha from 'fecha'
import clickoutside from '@/directives/clickoutside'
import { isValidDate, isValidRange, isDateObejct, isPlainObject, formatDate, parseDate, throttle } from '@/utils/index'
import { transformDate, transformDateRange } from '@/utils/transform'
import { isValidDate, isValidRangeDate, isDateObejct, isPlainObject, formatDate, parseDate, throttle } from '@/utils/index'
import { transformDate } from '@/utils/transform'
import CalendarPanel from './calendar.vue'
import locale from '@/mixins/locale'
import Languages from '@/locale/languages'
Expand Down Expand Up @@ -141,7 +141,7 @@ export default {
default: 'zh'
},
format: {
type: String,
type: [String, Object],
default: 'YYYY-MM-DD'
},
dateFormat: {
Expand Down Expand Up @@ -227,12 +227,17 @@ export default {
},
computed: {
transform () {
const obj = this.range ? transformDateRange : transformDate
const type = this.valueType
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 () {
if (isPlainObject(this.lang)) {
Expand All @@ -250,12 +255,14 @@ export default {
if (this.userInput !== null) {
return this.userInput
}
const date = this.transform.value2date(this.value, this.format)
const { value2date } = this.transform
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]
? `${this.stringify(date[0])} ${this.rangeSeparator} ${this.stringify(date[1])}`
return this.isValidRangeValue(this.value)
? `${this.stringify(value2date(this.value[0]))} ${this.rangeSeparator} ${this.stringify(value2date(this.value[1]))}`
: ''
},
computedWidth () {
Expand All @@ -265,7 +272,7 @@ export default {
return this.width
},
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 () {
return String(this.type).toLowerCase()
Expand Down Expand Up @@ -314,6 +321,9 @@ export default {
if (this.dateFormat) {
return this.dateFormat
}
if (typeof this.format !== 'string') {
return 'YYYY-MM-DD'
}
if (this.innerType === 'date') {
return this.format
}
Expand Down Expand Up @@ -348,11 +358,24 @@ export default {
this.handleValueChange(this.value)
this.displayPopup()
},
stringify (date, format) {
return formatDate(date, format || this.format)
stringify (date) {
return (isPlainObject(this.format) && typeof this.format.stringify === 'function')
? this.format.stringify(date)
: formatDate(date, this.format)
},
parseDate (value, format) {
return parseDate(value, format || this.format)
parse (value) {
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) {
return isDateObejct(a) && isDateObejct(b) && a.getTime() === b.getTime()
Expand All @@ -374,7 +397,7 @@ export default {
this.$emit('clear')
},
confirmDate () {
const valid = this.range ? isValidRange(this.currentValue) : isValidDate(this.currentValue)
const valid = this.range ? isValidRangeDate(this.currentValue) : isValidDate(this.currentValue)
if (valid) {
this.updateDate(true)
}
Expand All @@ -394,10 +417,19 @@ export default {
return true
},
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) {
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) {
this.currentValue = date
Expand Down Expand Up @@ -497,8 +529,8 @@ export default {
if (this.range) {
const range = value.split(` ${this.rangeSeparator} `)
if (range.length === 2) {
const start = this.parseDate(range[0], this.format)
const end = this.parseDate(range[1], this.format)
const start = this.parse(range[0])
const end = this.parse(range[1])
if (start && end && !checkDate(start, null, end) && !checkDate(end, start, null)) {
this.currentValue = [start, end]
this.updateDate(true)
Expand All @@ -507,7 +539,7 @@ export default {
}
}
} else {
const date = this.parseDate(value, this.format)
const date = this.parse(value)
if (date && !checkDate(date, null, null)) {
this.currentValue = date
this.updateDate(true)
Expand Down
2 changes: 1 addition & 1 deletion src/utils/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export function isValidDate (date) {
return !isNaN(new Date(date).getTime())
}

export function isValidRange (date) {
export function isValidRangeDate (date) {
return (
Array.isArray(date) &&
date.length === 2 &&
Expand Down
32 changes: 2 additions & 30 deletions src/utils/transform.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { isValidDate, isValidRange, parseDate, formatDate } from './index'
import { isValidDate } from './index'

export const transformDate = {
date: {
Expand All @@ -7,34 +7,6 @@ export const transformDate = {
},
timestamp: {
value2date: (value) => isValidDate(value) ? new Date(value) : null,
date2value: (date) => isValidDate(date) ? new Date(date).getTime() : null
},
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))
date2value: (date) => date && new Date(date).getTime()
}
}
11 changes: 1 addition & 10 deletions test/index.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import CalendarPanel from '../src/calendar.vue'
import DatePanel from '../src/panel/date'
import TimePanel from '../src/panel/time'
import YearPanel from '../src/panel/year'
import { transformDate, transformDateRange } from '../src/utils/transform'
import { transformDate } from '../src/utils/transform'

let wrapper

Expand All @@ -24,15 +24,6 @@ describe('datepicker', () => {
expect(vm.transform).toBe(transformDate.date)
wrapper.setProps({ valueType: '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
wrapper.setProps({ valueType: {
Expand Down
25 changes: 7 additions & 18 deletions test/transform.spec.js
Original file line number Diff line number Diff line change
@@ -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 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 obj = range ? transformDateRange : transformDate
const testfn = ({ type, value, date, err = null }) => it(`${type}}`, () => {
const obj = transformDate
const typeObj = obj[type]
expect(typeObj.value2date(err, format)).toEqual(err)
expect(typeObj.value2date(value, format)).toEqual(date)
expect(typeObj.date2value(err, format)).toEqual(err)
expect(typeObj.date2value(date, format)).toEqual(value)
expect(typeObj.value2date(err)).toEqual(err)
expect(typeObj.value2date(value)).toEqual(date)
expect(typeObj.date2value(err)).toEqual(err)
expect(typeObj.date2value(date)).toEqual(value)
})

describe('transformDate', () => {
testfn({ type: 'date', value: time, date: time })
testfn({ type: 'format', value: text, 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 })
})

0 comments on commit c801516

Please sign in to comment.