diff --git a/docs/en-US/component/date-picker.md b/docs/en-US/component/date-picker.md
index 9dfbfe08b2..6c4c2275c0 100644
--- a/docs/en-US/component/date-picker.md
+++ b/docs/en-US/component/date-picker.md
@@ -130,6 +130,38 @@ date-picker/default-time
:::
+## Custom content
+
+The content of cell can be customized, in scoped-slot you can get the cell data.
+
+:::demo
+
+date-picker/custom-content
+
+:::
+
+For data details, please refer:
+
+```ts
+interface DateCell {
+ column: number
+ customClass: string
+ disabled: boolean
+ end: boolean
+ inRange: boolean
+ row: number
+ selected: Dayjs
+ isCurrent: boolean
+ isSelected: boolean
+ start: boolean
+ text: number
+ timestamp: number
+ date: Date
+ dayjs: Dayjs
+ type: 'normal' | 'today' | 'week' | 'next-month' | 'prev-month'
+}
+```
+
## Localization
The default locale of is English, if you need to use other languages, please check [Internationalization](/en-US/guide/i18n)
@@ -183,4 +215,5 @@ Note, date time locale (month name, first day of the week ...) are also configur
| Name | Description |
| --------------- | ------------------------------ |
+| default | custom cell content |
| range-separator | custom range separator content |
diff --git a/docs/examples/date-picker/custom-content.vue b/docs/examples/date-picker/custom-content.vue
new file mode 100644
index 0000000000..c062664d76
--- /dev/null
+++ b/docs/examples/date-picker/custom-content.vue
@@ -0,0 +1,83 @@
+
+
+
+
+
+ {{ cell.text }}
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/components/date-picker/__tests__/date-picker.spec.ts b/packages/components/date-picker/__tests__/date-picker.spec.ts
index 18fdb6f55d..6ed88607fa 100644
--- a/packages/components/date-picker/__tests__/date-picker.spec.ts
+++ b/packages/components/date-picker/__tests__/date-picker.spec.ts
@@ -241,6 +241,39 @@ describe('DatePicker', () => {
expect(attr).toEqual('false')
})
+ it('custom content', async () => {
+ const wrapper = _mount(
+ `
+
+
+
+ `,
+ () => ({ value: '' }),
+ {
+ mounted() {
+ this.$refs.input.focus()
+ },
+ }
+ )
+ await nextTick()
+ const input = wrapper.find('input')
+ input.trigger('blur')
+ input.trigger('focus')
+ await nextTick()
+ {
+ ;(document.querySelector('td.available .cell') as HTMLElement).click()
+ }
+ input.trigger('focus')
+ await nextTick()
+ expect(
+ document.querySelector('td.available .cell').classList.contains('current')
+ ).toBeTruthy()
+ })
+
describe('value-format', () => {
it('with literal string', async () => {
const day = dayjs()
diff --git a/packages/components/date-picker/src/date-picker-com/basic-cell-render.ts b/packages/components/date-picker/src/date-picker-com/basic-cell-render.ts
new file mode 100644
index 0000000000..df8bf2df60
--- /dev/null
+++ b/packages/components/date-picker/src/date-picker-com/basic-cell-render.ts
@@ -0,0 +1,36 @@
+import { h, defineComponent, inject } from 'vue'
+import { buildProps, definePropType } from '@element-plus/utils/props'
+import { ROOT_PICKER_INJECTION_KEY } from '../date-picker.type'
+import type { DateCell } from '../date-picker.type'
+
+export default defineComponent({
+ name: 'ElDatePickerCell',
+ props: buildProps({
+ cell: {
+ type: definePropType(Array),
+ },
+ }),
+ setup(props) {
+ const picker = inject(ROOT_PICKER_INJECTION_KEY)
+ return () => {
+ const cell = props.cell
+ return picker?.ctx.slots.default
+ ? picker.ctx.slots.default(cell)
+ : h(
+ 'div',
+ {
+ class: 'el-date-table-cell',
+ },
+ [
+ h(
+ 'span',
+ {
+ class: 'el-date-table-cell__text',
+ },
+ [cell?.text]
+ ),
+ ]
+ )
+ }
+ },
+})
diff --git a/packages/components/date-picker/src/date-picker-com/basic-date-table.vue b/packages/components/date-picker/src/date-picker-com/basic-date-table.vue
index ff35c9d25d..208e61c3ef 100644
--- a/packages/components/date-picker/src/date-picker-com/basic-date-table.vue
+++ b/packages/components/date-picker/src/date-picker-com/basic-date-table.vue
@@ -25,11 +25,7 @@
:key="key_"
:class="getCellClasses(cell)"
>
-
-
- {{ cell.text }}
-
-
+
@@ -41,11 +37,16 @@ import { defineComponent, computed, ref } from 'vue'
import dayjs from 'dayjs'
import { useLocaleInject } from '@element-plus/hooks'
import { coerceTruthyValueToArray } from '@element-plus/utils/util'
+import ElDatePickerCell from './basic-cell-render'
import type { PropType } from 'vue'
import type { Dayjs } from 'dayjs'
+import type { DateCell } from '../date-picker.type'
export default defineComponent({
+ components: {
+ ElDatePickerCell,
+ },
props: {
date: {
type: Object as PropType,
@@ -81,7 +82,6 @@ export default defineComponent({
}),
},
},
-
emits: ['changerange', 'pick', 'select'],
setup(props, ctx) {
@@ -89,7 +89,7 @@ export default defineComponent({
// data
const lastRow = ref(null)
const lastColumn = ref(null)
- const tableRows = ref([[], [], [], [], [], []])
+ const tableRows = ref([[], [], [], [], [], []])
// todo better way to get Day.js locale object
const firstDayOfWeek = (props.date as any).$locale().weekStart || 7
@@ -162,6 +162,9 @@ export default defineComponent({
}
const index = i * 7 + j
const calTime = startDate.value.add(index - offset, 'day')
+ cell.dayjs = calTime
+ cell.date = calTime.toDate()
+ cell.timestamp = calTime.valueOf()
cell.type = 'normal'
const calEndDate =
@@ -222,6 +225,8 @@ export default defineComponent({
cell.selected = selectedDate.find(
(_) => _.valueOf() === calTime.valueOf()
)
+ cell.isSelected = !!cell.selected
+ cell.isCurrent = isCurrent(cell)
cell.disabled = props.disabledDate && props.disabledDate(cellDate)
cell.customClass =
props.cellClassName && props.cellClassName(cellDate)
@@ -241,6 +246,14 @@ export default defineComponent({
return rows_
})
+ const isCurrent = (cell): boolean => {
+ return (
+ props.selectionMode === 'day' &&
+ (cell.type === 'normal' || cell.type === 'today') &&
+ cellMatchesDate(cell, props.parsedValue)
+ )
+ }
+
const cellMatchesDate = (cell, date) => {
if (!date) return false
return dayjs(date)
@@ -249,7 +262,7 @@ export default defineComponent({
}
const getCellClasses = (cell) => {
- const classes = []
+ const classes: string[] = []
if ((cell.type === 'normal' || cell.type === 'today') && !cell.disabled) {
classes.push('available')
if (cell.type === 'today') {
@@ -259,11 +272,7 @@ export default defineComponent({
classes.push(cell.type)
}
- if (
- props.selectionMode === 'day' &&
- (cell.type === 'normal' || cell.type === 'today') &&
- cellMatchesDate(cell, props.parsedValue)
- ) {
+ if (isCurrent(cell)) {
classes.push('current')
}
@@ -337,10 +346,11 @@ export default defineComponent({
const handleClick = (event) => {
let target = event.target
- if (target.tagName === 'SPAN') {
- target = target.parentNode.parentNode
- }
- if (target.tagName === 'DIV') {
+
+ while (target) {
+ if (target.tagName === 'TD') {
+ break
+ }
target = target.parentNode
}
diff --git a/packages/components/date-picker/src/date-picker.ts b/packages/components/date-picker/src/date-picker.ts
index ca3024f5b1..267fe55390 100644
--- a/packages/components/date-picker/src/date-picker.ts
+++ b/packages/components/date-picker/src/date-picker.ts
@@ -17,7 +17,7 @@ import {
import DatePickPanel from './date-picker-com/panel-date-pick.vue'
import DateRangePickPanel from './date-picker-com/panel-date-range.vue'
import MonthRangePickPanel from './date-picker-com/panel-month-range.vue'
-
+import { ROOT_PICKER_INJECTION_KEY } from './date-picker.type'
import type { PropType } from 'vue'
import type { IDatePickerType } from './date-picker.type'
@@ -52,6 +52,9 @@ export default defineComponent({
emits: ['update:modelValue'],
setup(props, ctx) {
provide('ElPopperOptions', props.popperOptions)
+ provide(ROOT_PICKER_INJECTION_KEY, {
+ ctx,
+ })
const commonPicker = ref(null)
const refProps = {
...props,
diff --git a/packages/components/date-picker/src/date-picker.type.ts b/packages/components/date-picker/src/date-picker.type.ts
index ed29ce7f20..2c19405e6b 100644
--- a/packages/components/date-picker/src/date-picker.type.ts
+++ b/packages/components/date-picker/src/date-picker.type.ts
@@ -1,3 +1,6 @@
+import type { InjectionKey, SetupContext } from 'vue'
+import type { Dayjs } from 'dayjs'
+
export declare type IDatePickerType =
| 'year'
| 'month'
@@ -8,3 +11,29 @@ export declare type IDatePickerType =
| 'datetimerange'
| 'daterange'
| 'monthrange'
+
+type DateCellType = 'normal' | 'today' | 'week' | 'next-month' | 'prev-month'
+export interface DateCell {
+ column?: number
+ customClass?: string
+ disabled?: boolean
+ end?: boolean
+ inRange?: boolean
+ row?: number
+ selected?: Dayjs
+ isCurrent?: boolean
+ isSelected?: boolean
+ start?: boolean
+ text?: number
+ timestamp?: number
+ date?: Date
+ dayjs?: Dayjs
+ type?: DateCellType
+}
+
+interface DatePickerContext {
+ ctx: SetupContext
+}
+
+export const ROOT_PICKER_INJECTION_KEY: InjectionKey =
+ Symbol()
diff --git a/packages/components/time-picker/src/common/picker.vue b/packages/components/time-picker/src/common/picker.vue
index 8d95bb81d9..417b25d2cf 100644
--- a/packages/components/time-picker/src/common/picker.vue
+++ b/packages/components/time-picker/src/common/picker.vue
@@ -97,8 +97,10 @@
@change="handleEndChange"
/>
diff --git a/packages/components/time-picker/src/time-picker.ts b/packages/components/time-picker/src/time-picker.ts
index 19eb8fd56b..9ac9dc2f54 100644
--- a/packages/components/time-picker/src/time-picker.ts
+++ b/packages/components/time-picker/src/time-picker.ts
@@ -32,7 +32,6 @@ export default defineComponent({
commonPicker.value?.handleBlur()
},
}
-
provide('ElPopperOptions', props.popperOptions)
ctx.expose(refProps)
return () => {
diff --git a/packages/theme-chalk/src/date-picker/date-table.scss b/packages/theme-chalk/src/date-picker/date-table.scss
index 65936d5ef3..1607a48e06 100644
--- a/packages/theme-chalk/src/date-picker/date-table.scss
+++ b/packages/theme-chalk/src/date-picker/date-table.scss
@@ -8,25 +8,25 @@
@include when(week-mode) {
.#{$namespace}-date-table__row {
&:hover {
- div {
+ .el-date-table-cell {
background-color: var(--el-datepicker-inrange-background-color);
}
td.available:hover {
color: var(--el-datepicker-font-color);
}
- td:first-child div {
+ td:first-child .el-date-table-cell {
margin-left: 5px;
border-top-left-radius: 15px;
border-bottom-left-radius: 15px;
}
- td:last-child div {
+ td:last-child .el-date-table-cell {
margin-right: 5px;
border-top-right-radius: 15px;
border-bottom-right-radius: 15px;
}
}
- &.current div {
+ &.current .el-date-table-cell {
background-color: var(--el-datepicker-inrange-background-color);
}
}
@@ -41,22 +41,21 @@
cursor: pointer;
position: relative;
- & div {
+ @include b(date-table-cell) {
height: 30px;
padding: 3px 0;
box-sizing: border-box;
- }
-
- & span {
- width: 24px;
- height: 24px;
- display: block;
- margin: 0 auto;
- line-height: 24px;
- position: absolute;
- left: 50%;
- transform: translateX(-50%);
- border-radius: 50%;
+ @include b(date-table-cell__text) {
+ width: 24px;
+ height: 24px;
+ display: block;
+ margin: 0 auto;
+ line-height: 24px;
+ position: absolute;
+ left: 50%;
+ transform: translateX(-50%);
+ border-radius: 50%;
+ }
}
&.next-month,
@@ -66,12 +65,12 @@
&.today {
position: relative;
- span {
+ .el-date-table-cell__text {
color: var(--el-color-primary);
font-weight: bold;
}
- &.start-date span,
- &.end-date span {
+ &.start-date .el-date-table-cell__text,
+ &.end-date .el-date-table-cell__text {
color: $color-white;
}
}
@@ -80,47 +79,47 @@
color: var(--el-datepicker-hover-font-color);
}
- &.in-range div {
+ &.in-range .el-date-table-cell {
background-color: var(--el-datepicker-inrange-background-color);
&:hover {
background-color: var(--el-datepicker-inrange-hover-background-color);
}
}
- &.current:not(.disabled) span {
+ &.current:not(.disabled) .el-date-table-cell__text {
color: $color-white;
background-color: var(--el-datepicker-active-color);
}
- &.start-date div,
- &.end-date div {
+ &.start-date .el-date-table-cell,
+ &.end-date .el-date-table-cell {
color: $color-white;
}
- &.start-date span,
- &.end-date span {
+ &.start-date .el-date-table-cell__text,
+ &.end-date .el-date-table-cell__text {
background-color: var(--el-datepicker-active-color);
}
- &.start-date div {
+ &.start-date .el-date-table-cell {
margin-left: 5px;
border-top-left-radius: 15px;
border-bottom-left-radius: 15px;
}
- &.end-date div {
+ &.end-date .el-date-table-cell {
margin-right: 5px;
border-top-right-radius: 15px;
border-bottom-right-radius: 15px;
}
- &.disabled div {
+ &.disabled .el-date-table-cell {
background-color: $background-color-base;
opacity: 1;
cursor: not-allowed;
color: var(--el-text-color-placeholder);
}
- &.selected div {
+ &.selected .el-date-table-cell {
margin-left: 5px;
margin-right: 5px;
background-color: var(--el-datepicker-inrange-background-color);
@@ -130,7 +129,7 @@
}
}
- &.selected span {
+ &.selected .el-date-table-cell__text {
background-color: var(--el-datepicker-active-color);
color: $color-white;
border-radius: 15px;
diff --git a/packages/theme-chalk/src/date-picker/picker.scss b/packages/theme-chalk/src/date-picker/picker.scss
index 4cd6e17498..e7d6e4d913 100644
--- a/packages/theme-chalk/src/date-picker/picker.scss
+++ b/packages/theme-chalk/src/date-picker/picker.scss
@@ -125,6 +125,11 @@
svg {
vertical-align: middle;
}
+
+ &--hidden {
+ opacity: 0;
+ visibility: hidden;
+ }
}
}