mirror of
https://gitee.com/element-plus/element-plus.git
synced 2024-12-04 20:27:44 +08:00
refactor(components): [calendar] (#10155)
* refactor(components): [calendar] * Extract date-table logic code into a dedicated file. * chore: add an alias type export
This commit is contained in:
parent
4150baa7a3
commit
c7b8cf7e54
@ -5,3 +5,7 @@ export const ElCalendar = withInstall(Calendar)
|
||||
export default ElCalendar
|
||||
|
||||
export * from './src/calendar'
|
||||
export type {
|
||||
CalendarDateTableInstance,
|
||||
DateTableInstance,
|
||||
} from './src/instance'
|
||||
|
@ -2,7 +2,6 @@ import { buildProps, definePropType, isObject } from '@element-plus/utils'
|
||||
import { rangeArr } from '@element-plus/components/time-picker'
|
||||
import type { ExtractPropTypes } from 'vue'
|
||||
import type { Dayjs } from 'dayjs'
|
||||
import type DateTable from './date-table.vue'
|
||||
|
||||
export type CalendarDateCellType = 'next' | 'prev' | 'current'
|
||||
export type CalendarDateCell = {
|
||||
@ -47,5 +46,3 @@ export const dateTableEmits = {
|
||||
pick: (value: Dayjs) => isObject(value),
|
||||
}
|
||||
export type DateTableEmits = typeof dateTableEmits
|
||||
|
||||
export type DateTableInstance = InstanceType<typeof DateTable>
|
||||
|
@ -35,22 +35,11 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed } from 'vue'
|
||||
import dayjs from 'dayjs'
|
||||
import localeData from 'dayjs/plugin/localeData.js'
|
||||
import { useLocale, useNamespace } from '@element-plus/hooks'
|
||||
import { rangeArr } from '@element-plus/components/time-picker'
|
||||
import { WEEK_DAYS } from '@element-plus/constants'
|
||||
import {
|
||||
dateTableEmits,
|
||||
dateTableProps,
|
||||
getMonthDays,
|
||||
getPrevMonthLastDays,
|
||||
toNestedArr,
|
||||
} from './date-table'
|
||||
import { useNamespace } from '@element-plus/hooks'
|
||||
import { dateTableEmits, dateTableProps } from './date-table'
|
||||
import { useDateTable } from './use-date-table'
|
||||
|
||||
import type { CalendarDateCell, CalendarDateCellType } from './date-table'
|
||||
import type { Dayjs } from 'dayjs'
|
||||
import type { CalendarDateCell } from './date-table'
|
||||
|
||||
defineOptions({
|
||||
name: 'DateTable',
|
||||
@ -59,88 +48,19 @@ defineOptions({
|
||||
const props = defineProps(dateTableProps)
|
||||
const emit = defineEmits(dateTableEmits)
|
||||
|
||||
dayjs.extend(localeData)
|
||||
const {
|
||||
isInRange,
|
||||
now,
|
||||
rows,
|
||||
weekDays,
|
||||
getFormattedDate,
|
||||
handlePickDay,
|
||||
getSlotData,
|
||||
} = useDateTable(props, emit)
|
||||
|
||||
const { t, lang } = useLocale()
|
||||
const nsTable = useNamespace('calendar-table')
|
||||
const nsDay = useNamespace('calendar-day')
|
||||
|
||||
const now = dayjs().locale(lang.value)
|
||||
// https://day.js.org/docs/en/i18n/locale-data
|
||||
const firstDayOfWeek: number = dayjs.localeData().firstDayOfWeek()
|
||||
|
||||
const isInRange = computed(() => !!props.range && !!props.range.length)
|
||||
|
||||
const rows = computed(() => {
|
||||
let days: CalendarDateCell[] = []
|
||||
if (isInRange.value) {
|
||||
const [start, end] = props.range!
|
||||
const currentMonthRange: CalendarDateCell[] = rangeArr(
|
||||
end.date() - start.date() + 1
|
||||
).map((index) => ({
|
||||
text: start.date() + index,
|
||||
type: 'current',
|
||||
}))
|
||||
|
||||
let remaining = currentMonthRange.length % 7
|
||||
remaining = remaining === 0 ? 0 : 7 - remaining
|
||||
const nextMonthRange: CalendarDateCell[] = rangeArr(remaining).map(
|
||||
(_, index) => ({
|
||||
text: index + 1,
|
||||
type: 'next',
|
||||
})
|
||||
)
|
||||
days = currentMonthRange.concat(nextMonthRange)
|
||||
} else {
|
||||
const firstDay = props.date.startOf('month').day()
|
||||
const prevMonthDays: CalendarDateCell[] = getPrevMonthLastDays(
|
||||
props.date,
|
||||
(firstDay - firstDayOfWeek + 7) % 7
|
||||
).map((day) => ({
|
||||
text: day,
|
||||
type: 'prev',
|
||||
}))
|
||||
const currentMonthDays: CalendarDateCell[] = getMonthDays(props.date).map(
|
||||
(day) => ({
|
||||
text: day,
|
||||
type: 'current',
|
||||
})
|
||||
)
|
||||
days = [...prevMonthDays, ...currentMonthDays]
|
||||
const remaining = 7 - (days.length % 7 || 7)
|
||||
const nextMonthDays: CalendarDateCell[] = rangeArr(remaining).map(
|
||||
(_, index) => ({
|
||||
text: index + 1,
|
||||
type: 'next',
|
||||
})
|
||||
)
|
||||
days = days.concat(nextMonthDays)
|
||||
}
|
||||
return toNestedArr(days)
|
||||
})
|
||||
|
||||
const weekDays = computed(() => {
|
||||
const start = firstDayOfWeek
|
||||
if (start === 0) {
|
||||
return WEEK_DAYS.map((_) => t(`el.datepicker.weeks.${_}`))
|
||||
} else {
|
||||
return WEEK_DAYS.slice(start)
|
||||
.concat(WEEK_DAYS.slice(0, start))
|
||||
.map((_) => t(`el.datepicker.weeks.${_}`))
|
||||
}
|
||||
})
|
||||
|
||||
const getFormattedDate = (day: number, type: CalendarDateCellType): Dayjs => {
|
||||
switch (type) {
|
||||
case 'prev':
|
||||
return props.date.startOf('month').subtract(1, 'month').date(day)
|
||||
case 'next':
|
||||
return props.date.startOf('month').add(1, 'month').date(day)
|
||||
case 'current':
|
||||
return props.date.date(day)
|
||||
}
|
||||
}
|
||||
|
||||
const getCellClass = ({ text, type }: CalendarDateCell) => {
|
||||
const classes: string[] = [type]
|
||||
if (type === 'current') {
|
||||
@ -155,21 +75,6 @@ const getCellClass = ({ text, type }: CalendarDateCell) => {
|
||||
return classes
|
||||
}
|
||||
|
||||
const handlePickDay = ({ text, type }: CalendarDateCell) => {
|
||||
const date = getFormattedDate(text, type)
|
||||
emit('pick', date)
|
||||
}
|
||||
|
||||
const getSlotData = ({ text, type }: CalendarDateCell) => {
|
||||
const day = getFormattedDate(text, type)
|
||||
return {
|
||||
isSelected: day.isSame(props.selectedDay),
|
||||
type: `${type}-month`,
|
||||
day: day.format('YYYY-MM-DD'),
|
||||
date: day.toDate(),
|
||||
}
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
/** @description toggle date panel */
|
||||
getFormattedDate,
|
||||
|
4
packages/components/calendar/src/instance.ts
Normal file
4
packages/components/calendar/src/instance.ts
Normal file
@ -0,0 +1,4 @@
|
||||
import type DateTable from './date-table.vue'
|
||||
|
||||
export type DateTableInstance = InstanceType<typeof DateTable>
|
||||
export type CalendarDateTableInstance = DateTableInstance
|
125
packages/components/calendar/src/use-date-table.ts
Normal file
125
packages/components/calendar/src/use-date-table.ts
Normal file
@ -0,0 +1,125 @@
|
||||
import { computed } from 'vue'
|
||||
import dayjs from 'dayjs'
|
||||
import localeData from 'dayjs/plugin/localeData.js'
|
||||
import { useLocale } from '@element-plus/hooks'
|
||||
import { rangeArr } from '@element-plus/components/time-picker'
|
||||
import { WEEK_DAYS } from '@element-plus/constants'
|
||||
import { getMonthDays, getPrevMonthLastDays, toNestedArr } from './date-table'
|
||||
|
||||
import type { SetupContext } from 'vue'
|
||||
import type { Dayjs } from 'dayjs'
|
||||
import type {
|
||||
CalendarDateCell,
|
||||
CalendarDateCellType,
|
||||
DateTableEmits,
|
||||
DateTableProps,
|
||||
} from './date-table'
|
||||
|
||||
export const useDateTable = (
|
||||
props: DateTableProps,
|
||||
emit: SetupContext<DateTableEmits>['emit']
|
||||
) => {
|
||||
dayjs.extend(localeData)
|
||||
// https://day.js.org/docs/en/i18n/locale-data
|
||||
const firstDayOfWeek: number = dayjs.localeData().firstDayOfWeek()
|
||||
|
||||
const { t, lang } = useLocale()
|
||||
const now = dayjs().locale(lang.value)
|
||||
|
||||
const isInRange = computed(() => !!props.range && !!props.range.length)
|
||||
|
||||
const rows = computed(() => {
|
||||
let days: CalendarDateCell[] = []
|
||||
if (isInRange.value) {
|
||||
const [start, end] = props.range!
|
||||
const currentMonthRange: CalendarDateCell[] = rangeArr(
|
||||
end.date() - start.date() + 1
|
||||
).map((index) => ({
|
||||
text: start.date() + index,
|
||||
type: 'current',
|
||||
}))
|
||||
|
||||
let remaining = currentMonthRange.length % 7
|
||||
remaining = remaining === 0 ? 0 : 7 - remaining
|
||||
const nextMonthRange: CalendarDateCell[] = rangeArr(remaining).map(
|
||||
(_, index) => ({
|
||||
text: index + 1,
|
||||
type: 'next',
|
||||
})
|
||||
)
|
||||
days = currentMonthRange.concat(nextMonthRange)
|
||||
} else {
|
||||
const firstDay = props.date.startOf('month').day()
|
||||
const prevMonthDays: CalendarDateCell[] = getPrevMonthLastDays(
|
||||
props.date,
|
||||
(firstDay - firstDayOfWeek + 7) % 7
|
||||
).map((day) => ({
|
||||
text: day,
|
||||
type: 'prev',
|
||||
}))
|
||||
const currentMonthDays: CalendarDateCell[] = getMonthDays(props.date).map(
|
||||
(day) => ({
|
||||
text: day,
|
||||
type: 'current',
|
||||
})
|
||||
)
|
||||
days = [...prevMonthDays, ...currentMonthDays]
|
||||
const remaining = 7 - (days.length % 7 || 7)
|
||||
const nextMonthDays: CalendarDateCell[] = rangeArr(remaining).map(
|
||||
(_, index) => ({
|
||||
text: index + 1,
|
||||
type: 'next',
|
||||
})
|
||||
)
|
||||
days = days.concat(nextMonthDays)
|
||||
}
|
||||
return toNestedArr(days)
|
||||
})
|
||||
|
||||
const weekDays = computed(() => {
|
||||
const start = firstDayOfWeek
|
||||
if (start === 0) {
|
||||
return WEEK_DAYS.map((_) => t(`el.datepicker.weeks.${_}`))
|
||||
} else {
|
||||
return WEEK_DAYS.slice(start)
|
||||
.concat(WEEK_DAYS.slice(0, start))
|
||||
.map((_) => t(`el.datepicker.weeks.${_}`))
|
||||
}
|
||||
})
|
||||
|
||||
const getFormattedDate = (day: number, type: CalendarDateCellType): Dayjs => {
|
||||
switch (type) {
|
||||
case 'prev':
|
||||
return props.date.startOf('month').subtract(1, 'month').date(day)
|
||||
case 'next':
|
||||
return props.date.startOf('month').add(1, 'month').date(day)
|
||||
case 'current':
|
||||
return props.date.date(day)
|
||||
}
|
||||
}
|
||||
|
||||
const handlePickDay = ({ text, type }: CalendarDateCell) => {
|
||||
const date = getFormattedDate(text, type)
|
||||
emit('pick', date)
|
||||
}
|
||||
|
||||
const getSlotData = ({ text, type }: CalendarDateCell) => {
|
||||
const day = getFormattedDate(text, type)
|
||||
return {
|
||||
isSelected: day.isSame(props.selectedDay),
|
||||
type: `${type}-month`,
|
||||
day: day.format('YYYY-MM-DD'),
|
||||
date: day.toDate(),
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
now,
|
||||
isInRange,
|
||||
rows,
|
||||
weekDays,
|
||||
getFormattedDate,
|
||||
handlePickDay,
|
||||
getSlotData,
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user