fix: date picker support value-format (#2120)

Co-authored-by: yangyu8 <yangyu8@kingsoft.com>
This commit is contained in:
msidolphin 2021-06-03 20:35:48 +08:00 committed by GitHub
parent 77631999d1
commit da622e10d1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 202 additions and 5 deletions

View File

@ -4,6 +4,7 @@ import dayjs from 'dayjs'
import 'dayjs/locale/zh-cn'
import { nextTick } from 'vue'
import DatePicker from '../src/date-picker'
import Input from '@element-plus/input'
const _mount = (template: string, data = () => ({}), otherObj?) => mount({
components: {
@ -192,6 +193,48 @@ describe('DatePicker', () => {
const attr = popperEl.getAttribute('aria-hidden')
expect(attr).toEqual('false')
})
describe('value-format', () => {
it('with literal string', async () => {
const day = dayjs()
const format = 'YYYY-MM-DD'
const valueFormat = '[Element-Plus] DD/MM YYYY'
const value = day.format(valueFormat)
const wrapper = _mount(`
<el-date-picker
ref="compo"
v-model="value"
type="date"
format="${format}"
value-format="${valueFormat}" />
<button @click="changeValue">click</button>
`, () => {
return {
value,
}
}, {
methods: {
changeValue () {
this.value = '[Element-Plus] 31/05 2021'
},
},
})
const vm = wrapper.vm as any
const input = wrapper.find('input')
input.trigger('blur')
input.trigger('focus')
await nextTick()
{
(document.querySelector('td.available') as HTMLElement).click()
}
await nextTick()
expect(vm.value).toBe(dayjs(`[Element-Plus] 01/${('0' + (day.month() + 1)).slice(-2)} ${day.year()}`, valueFormat).format(valueFormat))
wrapper.find('button').trigger('click')
await nextTick()
expect(wrapper.findComponent(Input).vm.modelValue).toBe('2021-05-31')
})
})
})
describe('DatePicker Navigation', () => {
@ -299,6 +342,29 @@ describe('MonthPicker', () => {
const vm = wrapper.vm as any
expect(vm.value.getMonth()).toBe(0)
})
it('value-format', async () => {
const valueFormat = '[Element-Plus] YYYY.MM'
const wrapper = _mount(`
<el-date-picker
type="month"
v-model="value"
value-format="${valueFormat}"
></el-date-picker>
`, () => ({ value: dayjs(new Date(2020, 7, 1)).format(valueFormat) }))
await nextTick()
expect(wrapper.findComponent(Input).vm.modelValue).toBe('2020-08')
const input = wrapper.find('input')
input.trigger('blur')
input.trigger('focus')
await nextTick()
{
(document.querySelector('.el-month-table a.cell') as HTMLElement).click()
}
await nextTick()
expect(wrapper.findComponent(Input).vm.modelValue).toBe('2020-01')
expect((wrapper.vm as any).value).toBe(dayjs(new Date(2020, 0, 1)).format(valueFormat))
})
})
describe('YearPicker', () => {
@ -333,6 +399,27 @@ describe('YearPicker', () => {
const vm = wrapper.vm as any
expect(vm.value.getFullYear()).toBe(2030)
})
it('value-format', async () => {
const valueFormat = '[Element-Plus] YYYY'
const wrapper = _mount(`
<el-date-picker
type="year"
v-model="value"
value-format="${valueFormat}"
></el-date-picker>
`, () => ({ value: dayjs(new Date(2005, 7, 1)).format(valueFormat) }))
await nextTick()
expect(wrapper.findComponent(Input).vm.modelValue).toBe('2005')
const input = wrapper.find('input')
input.trigger('blur')
input.trigger('focus')
await nextTick()
const cell = (document.querySelector('.el-year-table a.cell') as HTMLElement)
cell.click()
await nextTick()
expect((wrapper.vm as any).value).toBe(dayjs(new Date(Number.parseInt(cell.innerHTML.trim()), 0, 1)).format(valueFormat))
})
})
describe('WeekPicker', () => {
@ -595,6 +682,34 @@ describe('DateRangePicker', () => {
expect(startDate.length).toBe(1)
expect(endDate.length).toBe(1)
})
it('value-format', async () => {
const valueFormat = 'DD/MM YYYY'
const wrapper = _mount( `
<el-date-picker
v-model="value"
type="daterange"
format="YYYY-MM-DD"
value-format="${valueFormat}"
/>`, () => ({ value: [
dayjs(new Date(2021, 4, 2)).format(valueFormat),
dayjs(new Date(2021, 4, 12)).format(valueFormat),
] }))
await nextTick()
const [startInput, endInput] = wrapper.findAll('input')
expect(startInput.element.value).toBe('2021-05-02')
expect(endInput.element.value).toBe('2021-05-12')
startInput.trigger('blur')
startInput.trigger('focus')
await nextTick()
const panels = document.querySelectorAll('.el-date-range-picker__content')
expect(panels.length).toBe(2);
(panels[0].querySelector('td.available') as HTMLElement).click()
await nextTick();
(panels[1].querySelector('td.available') as HTMLElement).click()
await nextTick()
expect((wrapper.vm as any).value.toString()).toBe([ '01/05 2021', '01/06 2021' ].toString())
})
})
describe('MonthRange', () => {

View File

@ -130,12 +130,12 @@ import {
watch,
provide,
} from 'vue'
import dayjs from 'dayjs'
import dayjs, { Dayjs } from 'dayjs'
import { ClickOutside } from '@element-plus/directives'
import ElInput from '@element-plus/input'
import ElPopper from '@element-plus/popper'
import { EVENT_CODE } from '@element-plus/utils/aria'
import { useGlobalConfig } from '@element-plus/utils/util'
import { useGlobalConfig, isEmpty } from '@element-plus/utils/util'
import { elFormKey, elFormItemKey } from '@element-plus/form'
import { defaultProps } from './props'
import type { ElFormContext, ElFormItemContext } from '@element-plus/form'
@ -180,6 +180,15 @@ const valueEquals = function(a, b) {
return false
}
const parser = function(date: Date | string, format: string): Dayjs {
const day = isEmpty(format) ? dayjs(date) : dayjs(date, format)
return day.isValid() ? day : undefined
}
const formatter = function(date: Date, format: string) {
return isEmpty(format) ? date : dayjs(date).format(format)
}
export default defineComponent({
name: 'Picker',
components: {
@ -223,7 +232,13 @@ export default defineComponent({
}
const emitInput = val => {
if (!valueEquals(props.modelValue, val)) {
ctx.emit('update:modelValue', val)
let formatValue
if (Array.isArray(val)) {
formatValue = val.map(_ => formatter(_, props.valueFormat))
} else if(val) {
formatValue = formatter(val, props.valueFormat)
}
ctx.emit('update:modelValue', val ? formatValue : val)
}
}
const refInput = computed(() => {
@ -274,15 +289,18 @@ export default defineComponent({
}
} else {
if (Array.isArray(props.modelValue)) {
result = props.modelValue.map(_=>dayjs(_))
result = props.modelValue.map(_=> parser(_, props.valueFormat))
} else {
result = dayjs(props.modelValue as Date)
result = parser(props.modelValue as Date, props.valueFormat)
}
}
if (pickerOptions.value.getRangeAvaliableTime) {
result = pickerOptions.value.getRangeAvaliableTime(result)
}
if (Array.isArray(result) && result.some(_ => !_)) {
result = []
}
return result
})

View File

@ -13,6 +13,9 @@ export const defaultProps = {
format: {
type: String,
},
valueFormat: {
type: String as PropType<string>,
},
type: {
type: String,
default: '',

View File

@ -333,6 +333,17 @@ Pay attention to capitalization
format="YYYY/MM/DD">
</el-date-picker>
</div>
<div class="block">
<span class="demonstration">Use value-format</span>
<div class="demonstration">Value{{ value2 }}</div>
<el-date-picker
v-model="value2"
type="date"
placeholder="Pick a Date"
format="YYYY/MM/DD"
value-format="YYYY-MM-DD">
</el-date-picker>
</div>
</template>
<script>
@ -340,6 +351,7 @@ Pay attention to capitalization
data() {
return {
value1: '',
value2: ''
};
}
};
@ -407,6 +419,7 @@ Note, date time locale (month name, first day of the week ...) are also configed
| range-separator | range separator | string | — | '-' |
| default-value | optional, default date of the calendar | Date | anything accepted by `new Date()` | — |
| default-time | optional, the time value to use when selecting date range | Date[] | Array with length 2, each item is a Date. The first item for the start date and then second item for the end date | — |
| value-format | optional, format of binding value. If not specified, the binding value will be a Date object | string | see [date formats](#/en-US/component/date-picker#date-formats) | — |
| name | same as `name` in native input | string | — | — |
| unlink-panels | unlink two date-panels in range-picker | boolean | — | false |
| prefix-icon | Custom prefix icon class | string | — | el-icon-date |

View File

@ -335,6 +335,17 @@ Preste atención a la capitalización
format="YYYY/MM/DD">
</el-date-picker>
</div>
<div class="block">
<span class="demonstration">Use value-format</span>
<div class="demonstration">Value{{ value2 }}</div>
<el-date-picker
v-model="value2"
type="date"
placeholder="Pick a Date"
format="YYYY/MM/DD"
value-format="YYYY-MM-DD">
</el-date-picker>
</div>
</template>
<script>
@ -412,6 +423,7 @@ Note, date time locale (month name, first day of the week ...) are also configed
| range-separator | separador de rangos | string | — | '-' |
| default-value | opcional, valor por defecto para el calendario | Date | cualquiera aceptado por `new Date()` | — |
| default-time | optional, the time value to use when selecting date range | Date[] | Array with length 2, each item is a Date. The first item for the start date and then second item for the end date | — |
| value-format | opcional, formato del valor enlazado. Si no esta especificado, el valor enlazado será un objeto Date. | string | ver [date formats](#/es/component/date-picker#date-formats) | — |
| name | igual que `name` en el input nativo | string | — | — |
| unlink-panels | desvincular los dos paneles de fecha en el range-picker | boolean | — | false |
| prefix-icon | Clase personalizada para el icono prefijado | string | — | el-icon-date |

View File

@ -333,6 +333,17 @@ Attention à la capitalisation !
format="YYYY/MM/DD">
</el-date-picker>
</div>
<div class="block">
<span class="demonstration">Utilise value-format</span>
<div class="demonstration">Value{{ value2 }}</div>
<el-date-picker
v-model="value2"
type="date"
placeholder="Sélectionnez une date"
format="YYYY/MM/DD"
value-format="YYYY-MM-DD">
</el-date-picker>
</div>
</template>
<script>
@ -409,6 +420,7 @@ Note, date time locale (month name, first day of the week ...) are also configed
| range-separator | Séparateur de plage de dates. | string | — | '-' |
| default-value | Date par défaut du calendrier, optionnelle. | Date | Tout ce qui est accepté par `new Date()` | — |
| default-time | optional, the time value to use when selecting date range | Date[] | Array with length 2, each item is a Date. The first item for the start date and then second item for the end date | — |
| value-format | Format de la variable stockée, optionnel. Si non spécifié, la valeur sera un objet Date. | string | Voir [formats de date](#/fr-FR/component/date-picker#formats-de-date). | — |
| name | Identique au `name` de l'input natif | string | — | — |
| unlink-panels | Rend indépendants les deux panneaux de plage de dates. | boolean | — | false |
| prefix-icon | Icône de préfixe. | string | — | el-icon-date |

View File

@ -329,6 +329,17 @@ Check the list [here](https://day.js.org/docs/en/display/format#list-of-all-avai
format="yyyy/MM/dd">
</el-date-picker>
</div>
<div class="block">
<span class="demonstration">Use value-format</span>
<div class="demonstration">Value{{ value2 }}</div>
<el-date-picker
v-model="value2"
type="date"
placeholder="Pick a Date"
format="YYYY/MM/DD"
value-format="YYYY-MM-DD">
</el-date-picker>
</div>
</template>
<script>
@ -405,6 +416,7 @@ Note, date time locale (month name, first day of the week ...) are also configed
| range-separator | 範囲セパレータ | string | — | '-' |
| default-value | オプション、カレンダーのデフォルトの日付 | Date | anything accepted by `new Date()` | — |
| default-time | optional, the time value to use when selecting date range | Date[] | Array with length 2, each item is a Date. The first item for the start date and then second item for the end date | — |
| value-format | optional, format of binding value. If not specified, the binding value will be a Date object | string | see [date formats](#/en-US/component/date-picker#date-formats) | — |
| name | ネイティブ入力の `name` と同じ | string | — | — |
| unlink-panels | 範囲ピッカーで2つのデータパネルのリンクを解除する | boolean | — | false |
| prefix-icon | カスタムプレフィックスアイコン | string | — | el-icon-date |

View File

@ -331,6 +331,17 @@
format="YYYY 年 MM 月 DD 日">
</el-date-picker>
</div>
<div class="block">
<span class="demonstration">使用value-format</span>
<div class="demonstration">值:{{ value2 }}</div>
<el-date-picker
v-model="value2"
type="date"
placeholder="选择日期"
format="YYYY 年 MM 月 DD 日"
value-format="YYYY/MM/DD">
</el-date-picker>
</div>
</template>
<script>
@ -407,6 +418,7 @@
| range-separator | 选择范围时的分隔符 | string | — | '-' |
| default-value | 可选,选择器打开时默认显示的时间 | Date | 可被`new Date()`解析 | — |
| default-time | 范围选择时选中日期所使用的当日内具体时刻 | Date[] | 数组,长度为 2第一项指定开始日期的时刻第二项指定结束日期的时刻不指定会使用时刻 `00:00:00` | — |
| value-format | 可选,绑定值的格式。不指定则绑定值为 Date 对象 | string | 见[日期格式](#/zh-CN/component/date-picker#ri-qi-ge-shi) | — |
| name | 原生属性 | string | — | — |
| unlink-panels | 在范围选择器里取消两个日期面板之间的联动 | boolean | — | false |
| prefix-icon | 自定义头部图标的类名 | string | — | el-icon-date |