mirror of
https://github.com/tenrok/vue2-datepicker.git
synced 2026-06-11 09:12:27 +03:00
feat: add valueType to format binding value
This commit is contained in:
@@ -69,34 +69,51 @@ export default {
|
||||
```
|
||||
### Props
|
||||
|
||||
| Prop | Type | Default | Description |
|
||||
|---------------------|---------------|-------------|-----------------------------------------------------|
|
||||
| type | String | 'date' | select date type (date/datetime/year/month/time) |
|
||||
| range | Boolean | false | if true, the type is daterange or datetimerange |
|
||||
| format | String | YYYY-MM-DD | The parsing tokens are similar to the moment.js |
|
||||
| lang | String/Object | zh | Translation ([custom](#lang))(en/zh/es/pt-br/fr/ru/de/it/cs) |
|
||||
| clearable | Boolean | true | if false, don't show the clear icon |
|
||||
| confirm | Boolean | false | if true, need click the button to change the value |
|
||||
| editable | Boolean | true | if false, user cann't type it |
|
||||
| disabled | Boolean | false | Disable the component |
|
||||
| placeholder | String | | input placeholder text |
|
||||
| width | String/Number | 210 | input size |
|
||||
| append-to-body | Boolean | false | append the popup to body |
|
||||
| popupStyle | Object | | popup style(override the top, left style) |
|
||||
| not-before | String/Date | '' | Disable all dates before new Date(not-before) |
|
||||
| not-after | String/Date | '' | Disable all dates after new Date(not-after) |
|
||||
| disabled-days | Array/function| [] | Disable Days |
|
||||
| shortcuts | Boolean/Array | true | the shortcuts for the range picker |
|
||||
| time-picker-options | Object | {} | set timePickerOptions(start, step, end) |
|
||||
| minute-step | Number | 0 | if > 0 don't show the second picker(0 - 60) |
|
||||
| first-day-of-week | Number | 7 | set the first day of week (1-7) |
|
||||
| input-class | String | 'mx-input' | the input class name |
|
||||
| input-name | String | 'date' | the input name attr |
|
||||
| input-attr | Object | | the input attr(eg: { required: true, id: 'input'}) |
|
||||
| confirm-text | String | 'OK' | the default text to display on confirm button |
|
||||
| range-separator | String | '~' | the range separator text |
|
||||
| date-format | String | '' | format the time header and tooltip |
|
||||
| Prop | Type | Accepted Values | Default | Description |
|
||||
|---------------------|---------------|-----------------|-------------|-----------------------------------------------------|
|
||||
| type | String | date/datetime/year/month/time | 'date' | select date type |
|
||||
| range | Boolean | — | false | if true, the type is daterange or datetimerange |
|
||||
| format | String | — | YYYY-MM-DD | The parsing tokens are similar to the moment.js |
|
||||
| value-type | String/Object | date/format/timestamp | 'date' | type of binding value. If not specified, the binding value will be a Date object(see [detail](#value-type)) |
|
||||
| lang | String/Object | en/zh/es/pt-br/fr/ru/de/it/cs | zh | Translation (set [how to custom](#lang)) |
|
||||
| clearable | Boolean | — | true | if false, don't show the clear icon |
|
||||
| confirm | Boolean | — | false | if true, need click the button to change the value |
|
||||
| editable | Boolean | — | true | if false, user cann't type it |
|
||||
| disabled | Boolean | — | false | Disable the component |
|
||||
| placeholder | String | — | | input placeholder text |
|
||||
| width | String/Number | — | 210 | input size |
|
||||
| append-to-body | Boolean | — | false | append the popup to body |
|
||||
| popupStyle | Object | — | | popup style(override the top, left style) |
|
||||
| not-before | String/Date | — | '' | Disable all dates before new Date(not-before) |
|
||||
| not-after | String/Date | — | '' | Disable all dates after new Date(not-after) |
|
||||
| disabled-days | Array/function| — | [] | Disable Days |
|
||||
| shortcuts | Boolean/Array | — | true | the shortcuts for the range picker |
|
||||
| time-picker-options | Object | — | {} | set timePickerOptions(start, step, end) |
|
||||
| minute-step | Number | 0 - 60 | 0 | if > 0 don't show the second picker |
|
||||
| first-day-of-week | Number | 1 - 7 | 7 | set the first day of week |
|
||||
| input-class | String | — | 'mx-input' | the input class name |
|
||||
| input-attr | Object | — | | the input attr(eg: { required: true, id: 'input'}) |
|
||||
| confirm-text | String | — | 'OK' | the default text to display on confirm button |
|
||||
| range-separator | String | — | '~' | the range separator text |
|
||||
| date-format | String | — | '' | format the time header and tooltip |
|
||||
|
||||
#### value-type
|
||||
set the format of binding value
|
||||
|
||||
| Value | Description |
|
||||
|-----------------|-------------------------------------------|
|
||||
| date | binding value will be a Date object |
|
||||
| timestamp | binding value will be a timestamp number |
|
||||
| format | binding value will be the format string |
|
||||
|
||||
Advanced: You can also customize objects to implement two functions.
|
||||
```js
|
||||
{
|
||||
value2date: (value: any) => Date, // transform the binding value to calendar Date Object
|
||||
date2value: (date: Date) => any // transform the calendar Date Object to binding value
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
#### lang
|
||||
* String (en/zh/es/pt-br/fr/ru/de/it/cs)
|
||||
|
||||
+46
-26
@@ -69,32 +69,52 @@ export default {
|
||||
```
|
||||
### Props
|
||||
|
||||
| Prop | Type | Default | Description
|
||||
|---------------------|---------------|-------------|-----------------------------------------------------
|
||||
| type | String | 'date' | 选择日期或日期时间(可选:date,datetime,year,month,time)
|
||||
| range | Boolean | false | 如果是true, 显示日历范围选择
|
||||
| format | String | YYYY-MM-DD | 格式化显示日期 api类似moment.js
|
||||
| lang | String/Object | zh | 选择语言或自定义 (en/zh/es/pt-br/fr/ru/de/it/cs)(custom)
|
||||
| clearable | Boolean | true | 如果设置false, 不显示清除图标
|
||||
| confirm | Boolean | false | 如果是true, 显示确认按钮且需要确认才更新时间
|
||||
| editable | Boolean | true | 如果是false, 用户不能手动输入更新日期
|
||||
| disabled | Boolean | false | 禁用组件
|
||||
| placeholder | String | | 输入框placeholder
|
||||
| width | String/Number | 210 | 设置宽度
|
||||
| append-to-body | Boolean | false | 弹出层放到body下面
|
||||
| popup-style | Object | | 弹出层的样式(可以覆盖left,top样式)
|
||||
| not-before | String/Date | '' | 禁止选择这个时间之前的时间
|
||||
| not-after | String/Date | '' | 禁止选择这个时间之前=后的时间
|
||||
| disabled-days | Array/function| [] | 自定义禁止的日期
|
||||
| shortcuts | Boolean/Array | true | 自定义范围选择的时候快捷选项(见下表)
|
||||
| time-picker-options | Object | {} | 自定义时间选择的开始,结束,步进(见下表)
|
||||
| minute-step | Number | 0 | 设置分钟的步进, 设置大于0不显示秒的选择(0-60)
|
||||
| first-day-of-week | Number | 7 | 设置日历星期几开头(1-7)
|
||||
| input-class | String | 'mx-input' | 自定义输入框的类名
|
||||
| input-name | String | 'date' | 自定义input 的 name 属性
|
||||
| confirm-text | String | 'OK' | 确认按钮的名称
|
||||
| range-separator | String | '~' | range 分隔符
|
||||
| date-format | String | '' | 格式化时间组件头部和日历的tooltip,默认是format字段去除时间的格式化
|
||||
| 属性 | 类型 | 可选值 | 默认值 | 描述
|
||||
|---------------------|---------------| ---------------------- |-------------| -----------
|
||||
| type | String | date,datetime,year,month,time | 'date' | 选择日期或日期时间
|
||||
| range | Boolean | - | false | 如果是true, 显示日历范围选择
|
||||
| format | String | - | YYYY-MM-DD | 格式化显示日期 api类似moment.js
|
||||
| value-type | String/Object | date/format/timestamp | 'date' | 设置绑定值的格式([详情](#value-type)) |
|
||||
| lang | String/Object | en/zh/es/pt-br/fr/ru/de/it/cs| zh | 选择语言或自定义 ([自定义](#lang))
|
||||
| clearable | Boolean | - | true | 如果设置false, 不显示清除图标
|
||||
| confirm | Boolean | - | false | 如果是true, 显示确认按钮且需要确认才更新时间
|
||||
| editable | Boolean | - | true | 如果是false, 用户不能手动输入更新日期
|
||||
| disabled | Boolean | - | false | 禁用组件
|
||||
| placeholder | String | - | | 输入框placeholder
|
||||
| width | String/Number | - | 210 | 设置宽度
|
||||
| append-to-body | Boolean | - | false | 弹出层放到body下面
|
||||
| popup-style | Object | - | | 弹出层的样式(可以覆盖left,top样式)
|
||||
| not-before | String/Date | - | '' | 禁止选择这个时间之前的时间
|
||||
| not-after | String/Date | - | '' | 禁止选择这个时间之前=后的时间
|
||||
| disabled-days | Array/function| - | [] | 自定义禁止的日期
|
||||
| shortcuts | Boolean/Array | - | true | 自定义范围选择的时候快捷选项(见下表)
|
||||
| time-picker-options | Object | - | {} | 自定义时间选择的开始,结束,步进(见下表)
|
||||
| minute-step | Number | 0 - 60 | 0 | 设置分钟的步进, 设置大于0不显示秒的选择(0-60)
|
||||
| first-day-of-week | Number | 1 - 7 | 7 | 设置日历星期几开头
|
||||
| input-class | String | - | 'mx-input' | 自定义input元素的类名
|
||||
| input-attr | Object | — | | 自定义input元是的属性(eg: { required: true, id: 'input', name:'date'})
|
||||
| confirm-text | String | - | 'OK' | 确认按钮的名称
|
||||
| range-separator | String | - | '~' | range 分隔符
|
||||
| date-format | String | - | '' | 格式化时间组件头部和日历的tooltip,默认是format字段去除时间的格式化
|
||||
|
||||
|
||||
#### value-type
|
||||
设置绑定值的格式
|
||||
|
||||
| 可选值 | 描述
|
||||
|-----------------|---------------------------------------
|
||||
| date | 返回的绑定值是Date对象
|
||||
| timestamp | 返回的绑定值是时间戳数字
|
||||
| format | 返回的绑定值是通过`format`属性格式化的值
|
||||
|
||||
高级: 也可以传入一个自定义实现包含2个函数的对象
|
||||
```js
|
||||
{
|
||||
value2date: (value: any) => Date, // 转化绑定值到日历时间对象
|
||||
date2value: (date: Date) => any // 转化日历时间对象到绑定值
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
#### lang
|
||||
* String (en/zh/es/pt-br/fr/ru/de/it/cs)
|
||||
|
||||
+32
-17
@@ -109,6 +109,7 @@
|
||||
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 CalendarPanel from './calendar.vue'
|
||||
import locale from '@/mixins/locale'
|
||||
import Languages from '@/locale/languages'
|
||||
@@ -123,6 +124,12 @@ export default {
|
||||
},
|
||||
props: {
|
||||
value: null,
|
||||
valueType: {
|
||||
default: 'date',
|
||||
validator: function (value) {
|
||||
return ['timestamp', 'format', 'date'].indexOf(value) !== -1 || isPlainObject(value)
|
||||
}
|
||||
},
|
||||
placeholder: {
|
||||
type: String,
|
||||
default: null
|
||||
@@ -217,6 +224,14 @@ export default {
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
transform () {
|
||||
const obj = this.range ? transformDateRange : transformDate
|
||||
const type = this.valueType
|
||||
if (isPlainObject(type)) {
|
||||
return { ...obj.date, ...type }
|
||||
}
|
||||
return obj[type] || obj.date
|
||||
},
|
||||
language () {
|
||||
if (isPlainObject(this.lang)) {
|
||||
return { ...Languages.en, ...this.lang }
|
||||
@@ -233,11 +248,12 @@ export default {
|
||||
if (this.userInput !== null) {
|
||||
return this.userInput
|
||||
}
|
||||
const date = this.transform.value2date(this.value, this.format)
|
||||
if (!this.range) {
|
||||
return isValidDate(this.value) ? this.stringify(this.value) : ''
|
||||
return date ? this.stringify(date) : ''
|
||||
}
|
||||
return isValidRange(this.value)
|
||||
? `${this.stringify(this.value[0])} ${this.rangeSeparator} ${this.stringify(this.value[1])}`
|
||||
return Array.isArray(date) && date[0] && date[1]
|
||||
? `${this.stringify(date[0])} ${this.rangeSeparator} ${this.stringify(date[1])}`
|
||||
: ''
|
||||
},
|
||||
computedWidth () {
|
||||
@@ -264,28 +280,28 @@ export default {
|
||||
{
|
||||
text: pickers[0],
|
||||
onClick (self) {
|
||||
self.currentValue = [ new Date(), new Date(Date.now() + 3600 * 1000 * 24 * 7) ]
|
||||
self.currentValue = [new Date(), new Date(Date.now() + 3600 * 1000 * 24 * 7)]
|
||||
self.updateDate(true)
|
||||
}
|
||||
},
|
||||
{
|
||||
text: pickers[1],
|
||||
onClick (self) {
|
||||
self.currentValue = [ new Date(), new Date(Date.now() + 3600 * 1000 * 24 * 30) ]
|
||||
self.currentValue = [new Date(), new Date(Date.now() + 3600 * 1000 * 24 * 30)]
|
||||
self.updateDate(true)
|
||||
}
|
||||
},
|
||||
{
|
||||
text: pickers[2],
|
||||
onClick (self) {
|
||||
self.currentValue = [ new Date(Date.now() - 3600 * 1000 * 24 * 7), new Date() ]
|
||||
self.currentValue = [new Date(Date.now() - 3600 * 1000 * 24 * 7), new Date()]
|
||||
self.updateDate(true)
|
||||
}
|
||||
},
|
||||
{
|
||||
text: pickers[3],
|
||||
onClick (self) {
|
||||
self.currentValue = [ new Date(Date.now() - 3600 * 1000 * 24 * 30), new Date() ]
|
||||
self.currentValue = [new Date(Date.now() - 3600 * 1000 * 24 * 30), new Date()]
|
||||
self.updateDate(true)
|
||||
}
|
||||
}
|
||||
@@ -346,7 +362,7 @@ export default {
|
||||
if (typeof range.onClick === 'function') {
|
||||
return range.onClick(this)
|
||||
}
|
||||
this.currentValue = [ new Date(range.start), new Date(range.end) ]
|
||||
this.currentValue = [new Date(range.start), new Date(range.end)]
|
||||
this.updateDate(true)
|
||||
},
|
||||
clearDate () {
|
||||
@@ -360,7 +376,7 @@ export default {
|
||||
if (valid) {
|
||||
this.updateDate(true)
|
||||
}
|
||||
this.$emit('confirm', this.currentValue)
|
||||
this.emitDate('confirm')
|
||||
this.closePopup()
|
||||
},
|
||||
updateDate (confirm = false) {
|
||||
@@ -371,16 +387,15 @@ export default {
|
||||
if (equal) {
|
||||
return false
|
||||
}
|
||||
this.$emit('input', this.currentValue)
|
||||
this.$emit('change', this.currentValue)
|
||||
this.emitDate('input')
|
||||
this.emitDate('change')
|
||||
return true
|
||||
},
|
||||
emitDate (eventName) {
|
||||
this.$emit(eventName, this.transform.date2value(this.currentValue, this.format))
|
||||
},
|
||||
handleValueChange (value) {
|
||||
if (!this.range) {
|
||||
this.currentValue = isValidDate(value) ? new Date(value) : null
|
||||
} else {
|
||||
this.currentValue = isValidRange(value) ? [new Date(value[0]), new Date(value[1])] : [null, null]
|
||||
}
|
||||
this.currentValue = this.transform.value2date(value, this.format)
|
||||
},
|
||||
selectDate (date) {
|
||||
this.currentValue = date
|
||||
@@ -484,7 +499,7 @@ export default {
|
||||
const start = this.parseDate(range[0], this.format)
|
||||
const end = this.parseDate(range[1], this.format)
|
||||
if (start && end && !checkDate(start, null, end) && !checkDate(end, start, null)) {
|
||||
this.currentValue = [ start, end ]
|
||||
this.currentValue = [start, end]
|
||||
this.updateDate(true)
|
||||
this.closePopup()
|
||||
return
|
||||
|
||||
+1
-1
@@ -66,7 +66,7 @@ export function parseDate (value, format) {
|
||||
try {
|
||||
return fecha.parse(value, format)
|
||||
} catch (e) {
|
||||
return false
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
import { isValidDate, isValidRange, parseDate, formatDate } from './index'
|
||||
|
||||
export const transformDate = {
|
||||
date: {
|
||||
value2date: (value) => isValidDate(value) ? new Date(value) : null,
|
||||
date2value: (date) => date
|
||||
},
|
||||
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))
|
||||
}
|
||||
}
|
||||
@@ -5,6 +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'
|
||||
|
||||
let wrapper
|
||||
|
||||
@@ -13,6 +14,35 @@ afterEach(() => {
|
||||
})
|
||||
|
||||
describe('datepicker', () => {
|
||||
it('prop: valueType', () => {
|
||||
wrapper = mount(DatePicker, {
|
||||
propsData: {
|
||||
value: new Date(2018, 4, 2)
|
||||
}
|
||||
})
|
||||
const vm = wrapper.vm
|
||||
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: {
|
||||
date2value: fn,
|
||||
value2date: fn
|
||||
}})
|
||||
expect(vm.transform).toHaveProperty('date2value', fn)
|
||||
expect(vm.transform).toHaveProperty('value2date', fn)
|
||||
})
|
||||
|
||||
it('prop: inputAttr', () => {
|
||||
wrapper = mount(DatePicker, {
|
||||
propsData: {
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
import lang from '../src/locale/languages'
|
||||
|
||||
const testLang = (key) => it(key, () => {
|
||||
expect(lang[key].days).toHaveLength(7)
|
||||
expect(lang[key].months).toHaveLength(12)
|
||||
expect(lang[key].pickers).toHaveLength(4)
|
||||
})
|
||||
|
||||
describe('transformDate', () => {
|
||||
Object.keys(lang).forEach(key => testLang(key))
|
||||
})
|
||||
@@ -0,0 +1,29 @@
|
||||
import { transformDate, transformDateRange } 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 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)
|
||||
})
|
||||
|
||||
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 })
|
||||
})
|
||||
Reference in New Issue
Block a user