feat(Calendar): add top-info、bottom-info slot (#8716)

This commit is contained in:
neverland 2021-05-18 10:09:02 +08:00 committed by GitHub
parent c0fa715cf4
commit db41f5ad44
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 82 additions and 21 deletions

View File

@ -416,6 +416,7 @@ export default defineComponent({
const showMonthTitle = index !== 0 || !props.showSubtitle; const showMonthTitle = index !== 0 || !props.showSubtitle;
return ( return (
<CalendarMonth <CalendarMonth
v-slots={pick(slots, ['top-info', 'bottom-info'])}
ref={setMonthRefs(index)} ref={setMonthRefs(index)}
date={date} date={date}
currentDate={state.currentDate} currentDate={state.currentDate}

View File

@ -44,7 +44,7 @@ export default defineComponent({
emits: ['click'], emits: ['click'],
setup(props, { emit }) { setup(props, { emit, slots }) {
const style = computed(() => { const style = computed(() => {
const { item, index, color, offset, rowHeight } = props; const { item, index, color, offset, rowHeight } = props;
const style: CSSProperties = { const style: CSSProperties = {
@ -84,17 +84,37 @@ export default defineComponent({
} }
}; };
const renderTopInfo = () => {
const { topInfo } = props.item;
if (topInfo || slots['top-info']) {
return (
<div class={bem('top-info')}>
{slots['top-info'] ? slots['top-info'](props.item) : topInfo}
</div>
);
}
};
const renderBottomInfo = () => {
const { bottomInfo } = props.item;
if (bottomInfo || slots['bottom-info']) {
return (
<div class={bem('bottom-info')}>
{slots['bottom-info']
? slots['bottom-info'](props.item)
: bottomInfo}
</div>
);
}
};
const renderContent = () => { const renderContent = () => {
const { item, color, rowHeight } = props; const { item, color, rowHeight } = props;
const { type, text, topInfo, bottomInfo } = item; const { type, text } = item;
const TopInfo = topInfo && <div class={bem('top-info')}>{topInfo}</div>; const Nodes = [renderTopInfo(), text, renderBottomInfo()];
const BottomInfo = bottomInfo && (
<div class={bem('bottom-info')}>{bottomInfo}</div>
);
const Nodes = [TopInfo, text, BottomInfo];
if (type === 'selected') { if (type === 'selected') {
return ( return (

View File

@ -1,7 +1,7 @@
import { ref, computed, PropType, defineComponent } from 'vue'; import { ref, computed, PropType, defineComponent } from 'vue';
// Utils // Utils
import { addUnit, setScrollTop, createNamespace } from '../utils'; import { addUnit, setScrollTop, createNamespace, pick } from '../utils';
import { getMonthEndDay } from '../datetime-picker/utils'; import { getMonthEndDay } from '../datetime-picker/utils';
import { import {
t, t,
@ -55,7 +55,7 @@ export default defineComponent({
emits: ['click', 'update-height'], emits: ['click', 'update-height'],
setup(props, { emit }) { setup(props, { emit, slots }) {
const [visible, setVisible] = useToggle(); const [visible, setVisible] = useToggle();
const daysRef = ref<HTMLElement>(); const daysRef = ref<HTMLElement>();
const monthRef = ref<HTMLElement>(); const monthRef = ref<HTMLElement>();
@ -230,6 +230,7 @@ export default defineComponent({
const renderDay = (item: CalendarDayItem, index: number) => ( const renderDay = (item: CalendarDayItem, index: number) => (
<CalendarDay <CalendarDay
v-slots={pick(slots, ['top-info', 'bottom-info'])}
item={item} item={item}
index={index} index={index}
color={props.color} color={props.color}

View File

@ -288,7 +288,7 @@ Following props are supported when the type is range
| Attribute | Description | Type | Default | | Attribute | Description | Type | Default |
| --- | --- | --- | --- | | --- | --- | --- | --- |
| max-range | Number of selectable days | _number \| string_ | Unlimitied | | max-range | Number of selectable days | _number \| string_ | Unlimited |
| range-prompt | Error message when exceeded max range | _string_ | `Choose no more than xx days` | | range-prompt | Error message when exceeded max range | _string_ | `Choose no more than xx days` |
| allow-same-day | Whether the start and end time of the range is allowed on the same day | _boolean_ | `false` | | allow-same-day | Whether the start and end time of the range is allowed on the same day | _boolean_ | `false` |
@ -298,7 +298,7 @@ Following props are supported when the type is multiple
| Attribute | Description | Type | Default | | Attribute | Description | Type | Default |
| --- | --- | --- | --- | | --- | --- | --- | --- |
| max-range | Max count of selectable days | _number \| string_ | Unlimitied | | max-range | Max count of selectable days | _number \| string_ | Unlimited |
| range-prompt | Error message when exceeded max count | _string_ | `Choose no more than xx days` | | range-prompt | Error message when exceeded max count | _string_ | `Choose no more than xx days` |
### Data Structure of Day ### Data Structure of Day
@ -327,10 +327,12 @@ Following props are supported when the type is multiple
### Slots ### Slots
| Name | Description | | Name | Description | SlotProps |
| ------ | ------------- | | --------------------- | ------------------------- | ---------- |
| title | Custom title | | title | Custom title | - |
| footer | Custom fotter | | footer | Custom footer | - |
| top-info `v3.0.17` | Custom top info of day | _day: Day_ |
| bottom-info `v3.0.17` | Custom bottom info of day | _day: Day_ |
### Methods ### Methods

View File

@ -333,10 +333,12 @@ export default {
### Slots ### Slots
| 名称 | 说明 | | 名称 | 说明 | 参数 |
| ------ | ------------------ | | --------------------- | ------------------------ | ---------- |
| title | 自定义标题 | | title | 自定义标题 | - |
| footer | 自定义底部区域内容 | | footer | 自定义底部区域内容 | - |
| top-info `v3.0.17` | 自定义日期上方的提示信息 | _day: Day_ |
| bottom-info `v3.0.17` | 自定义日期下方的提示信息 | _day: Day_ |
### 方法 ### 方法

View File

@ -924,6 +924,21 @@ exports[`row-height prop 1`] = `
</div> </div>
`; `;
exports[`should render top-info and bottom-info slot correctly 1`] = `
<div role="gridcell"
style="margin-left: 71.42857142857143%;"
class="van-calendar__day van-calendar__day--disabled"
>
<div class="van-calendar__top-info">
top: 1
</div>
1
<div class="van-calendar__bottom-info">
bottom: 1
</div>
</div>
`;
exports[`title & footer slot 1`] = ` exports[`title & footer slot 1`] = `
<div class="van-calendar"> <div class="van-calendar">
<div class="van-calendar__header"> <div class="van-calendar__header">

View File

@ -533,3 +533,23 @@ test('close event', async () => {
expect(onClose).toHaveBeenCalledTimes(1); expect(onClose).toHaveBeenCalledTimes(1);
}); });
test('should render top-info and bottom-info slot correctly', async () => {
const wrapper = mount(Calendar, {
props: {
minDate,
maxDate,
poppable: false,
defaultDate: minDate,
lazyRender: false,
},
slots: {
'top-info': (item) => 'top: ' + item.text,
'bottom-info': (item) => 'bottom: ' + item.text,
},
});
await later();
expect(wrapper.find('.van-calendar__day').html()).toMatchSnapshot();
});