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:
Jeremy 2022-10-20 20:03:02 +08:00 committed by GitHub
parent 4150baa7a3
commit c7b8cf7e54
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 146 additions and 111 deletions

View File

@ -5,3 +5,7 @@ export const ElCalendar = withInstall(Calendar)
export default ElCalendar
export * from './src/calendar'
export type {
CalendarDateTableInstance,
DateTableInstance,
} from './src/instance'

View File

@ -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>

View File

@ -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,

View File

@ -0,0 +1,4 @@
import type DateTable from './date-table.vue'
export type DateTableInstance = InstanceType<typeof DateTable>
export type CalendarDateTableInstance = DateTableInstance

View 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,
}
}