feat: migrate Calendar component

This commit is contained in:
chenjiahan 2020-08-09 21:31:44 +08:00
parent a6888944ea
commit 0dd713f361
9 changed files with 93 additions and 76 deletions

View File

@ -46,4 +46,5 @@ module.exports = [
'picker',
'dialog',
'toast',
'calendar',
];

View File

@ -24,16 +24,17 @@ Vant 遵循 [Semver](https://semver.org/lang/zh-CN/) 语义化版本规范。
以下改动是为了适配 Vue 3 的 v-model API 用法变更:
- Tabs: `v-model` 重命名为 `v-model:active`
- Popup: `v-model` 重命名为 `v-model:show`
- ActionSheet: `v-model` 重命名为 `v-model:show`
- Calendar: `v-model` 重命名为 `v-model:show`
- Circle: `v-model` 重命名为 `v-model:currentRate`
- Dialog: `v-model` 重命名为 `v-model:show`
- ShareSheet: `v-model` 重命名为 `v-model:show`
- ActionSheet: `v-model` 重命名为 `v-model:show`
- List: `v-model` 重命名为 `v-model:loading``error.sync` 重命名为 `v-model:error`
- Field: v-model 对应的属性 `value` 重命名为 `modelValue`,事件由 `input` 重命名为 `update:modelValue`
- Switch: v-model 对应的属性 `value` 重命名为 `modelValue`,事件由 `input` 重命名为 `update:modelValue`
- List: `v-model` 重命名为 `v-model:loading``error.sync` 重命名为 `v-model:error`
- Popup: `v-model` 重命名为 `v-model:show`
- Sidebar: v-model 对应的属性 `activeKey` 重命名为 `modelValue`,事件由 `input` 重命名为 `update:modelValue`
- ShareSheet: `v-model` 重命名为 `v-model:show`
- Switch: v-model 对应的属性 `value` 重命名为 `modelValue`,事件由 `input` 重命名为 `update:modelValue`
- Tabs: `v-model` 重命名为 `v-model:active`
- TreeSelect: `active-id.sync` 重命名为 `v-model:active-id`
- TreeSelect: `main-active-index.sync` 重命名为 `v-model:main-active-index`

View File

@ -21,7 +21,7 @@ The `confirm` event will be triggered after the date selection is completed.
```html
<van-cell title="Select Single Date" :value="date" @click="show = true" />
<van-calendar v-model="show" @confirm="onConfirm" />
<van-calendar v-model:show="show" @confirm="onConfirm" />
```
```js
@ -48,7 +48,7 @@ export default {
```html
<van-cell title="Select Multiple Date" :value="text" @click="show = true" />
<van-calendar v-model="show" type="multiple" @confirm="onConfirm" />
<van-calendar v-model:show="show" type="multiple" @confirm="onConfirm" />
```
```js
@ -74,7 +74,7 @@ You can select a date range after setting `type` to`range`. In range mode, the d
```html
<van-cell title="Select Date Range" :value="date" @click="show = true" />
<van-calendar v-model="show" type="range" @confirm="onConfirm" />
<van-calendar v-model:show="show" type="range" @confirm="onConfirm" />
```
```js
@ -103,7 +103,7 @@ export default {
Set `show-confirm` to `false` to hide the confirm button. In this case, the `confirm` event will be triggered immediately after the selection is completed.
```html
<van-calendar v-model="show" :show-confirm="false" />
<van-calendar v-model:show="show" :show-confirm="false" />
```
### Custom Color
@ -111,7 +111,7 @@ Set `show-confirm` to `false` to hide the confirm button. In this case, the `con
Use `color` prop to custom calendar color.
```html
<van-calendar v-model="show" color="#07c160" />
<van-calendar v-model:show="show" color="#07c160" />
```
### Custom Date Range
@ -119,7 +119,7 @@ Use `color` prop to custom calendar color.
Use `min-date` and `max-date` to custom date range.
```html
<van-calendar v-model="show" :min-date="minDate" :max-date="maxDate" />
<van-calendar v-model:show="show" :min-date="minDate" :max-date="maxDate" />
```
```js
@ -140,7 +140,7 @@ Use `confirm-text` and `confirm-disabled-text` to custom confirm text.
```html
<van-calendar
v-model="show"
v-model:show="show"
type="range"
confirm-text="OK"
confirm-disabled-text="Select End Time"
@ -152,7 +152,7 @@ Use `confirm-text` and `confirm-disabled-text` to custom confirm text.
Use `formatter` to custom day text.
```html
<van-calendar v-model="show" type="range" :formatter="formatter" />
<van-calendar v-model:show="show" type="range" :formatter="formatter" />
```
```js
@ -189,7 +189,7 @@ export default {
Use `position` to custom popup positioncan be set to `top``left``right`.
```html
<van-calendar v-model="show" :round="false" position="right" />
<van-calendar v-model:show="show" :round="false" position="right" />
```
### Max Range
@ -251,7 +251,7 @@ Following props are supported when the poppable is true
| Attribute | Description | Type | Default |
| --- | --- | --- | --- |
| v-model | Whether to show calendar | _boolean_ | `false` |
| v-model:show | Whether to show calendar | _boolean_ | `false` |
| position | Popup position, can be set to `top` `right` `left` | _string_ | `bottom` |
| round | Whether to show round corner | _boolean_ | `true` |
| close-on-popstate `v2.4.4` | Whether to close when popstate | _boolean_ | `true` |

View File

@ -21,7 +21,7 @@ Vue.use(Calendar);
```html
<van-cell title="选择单个日期" :value="date" @click="show = true" />
<van-calendar v-model="show" @confirm="onConfirm" />
<van-calendar v-model:show="show" @confirm="onConfirm" />
```
```js
@ -50,7 +50,7 @@ export default {
```html
<van-cell title="选择多个日期" :value="text" @click="show = true" />
<van-calendar v-model="show" type="multiple" @confirm="onConfirm" />
<van-calendar v-model:show="show" type="multiple" @confirm="onConfirm" />
```
```js
@ -76,7 +76,7 @@ export default {
```html
<van-cell title="选择日期区间" :value="date" @click="show = true" />
<van-calendar v-model="show" type="range" @confirm="onConfirm" />
<van-calendar v-model:show="show" type="range" @confirm="onConfirm" />
```
```js
@ -105,7 +105,7 @@ export default {
`show-confirm` 设置为 `false` 可以隐藏确认按钮,这种情况下选择完成后会立即触发 `confirm` 事件。
```html
<van-calendar v-model="show" :show-confirm="false" />
<van-calendar v-model:show="show" :show-confirm="false" />
```
### 自定义颜色
@ -113,7 +113,7 @@ export default {
通过 `color` 属性可以自定义日历的颜色,对选中日期和底部按钮生效。
```html
<van-calendar v-model="show" color="#07c160" />
<van-calendar v-model:show="show" color="#07c160" />
```
### 自定义日期范围
@ -121,7 +121,7 @@ export default {
通过 `min-date``max-date` 定义日历的范围。
```html
<van-calendar v-model="show" :min-date="minDate" :max-date="maxDate" />
<van-calendar v-model:show="show" :min-date="minDate" :max-date="maxDate" />
```
```js
@ -142,7 +142,7 @@ export default {
```html
<van-calendar
v-model="show"
v-model:show="show"
type="range"
confirm-text="完成"
confirm-disabled-text="请选择结束时间"
@ -154,7 +154,7 @@ export default {
通过传入 `formatter` 函数来对日历上每一格的内容进行格式化。
```html
<van-calendar v-model="show" type="range" :formatter="formatter" />
<van-calendar v-model:show="show" type="range" :formatter="formatter" />
```
```js
@ -191,7 +191,7 @@ export default {
通过 `position` 属性自定义弹出层的弹出位置,可选值为 `top``left``right`
```html
<van-calendar v-model="show" :round="false" position="right" />
<van-calendar v-model:show="show" :round="false" position="right" />
```
### 日期区间最大范围
@ -253,7 +253,7 @@ export default {
| 参数 | 说明 | 类型 | 默认值 |
| --- | --- | --- | --- |
| v-model | 是否显示日历弹窗 | _boolean_ | `false` |
| v-model:show | 是否显示日历弹窗 | _boolean_ | `false` |
| position | 弹出位置,可选值为 `top` `right` `left` | _string_ | `bottom` |
| round | 是否显示圆角弹窗 | _boolean_ | `true` |
| close-on-popstate `v2.4.4` | 是否在页面回退时自动关闭 | _boolean_ | `true` |

View File

@ -15,7 +15,7 @@ export default createComponent({
methods: {
genTitle() {
if (this.showTitle) {
const title = this.slots('title') || this.title || t('title');
const title = this.$slots.title?.() || this.title || t('title');
return <div class={bem('header-title')}>{title}</div>;
}
},

View File

@ -31,6 +31,8 @@ export default createComponent({
firstDayOfWeek: Number,
},
emits: ['click'],
data() {
return {
visible: false,
@ -183,18 +185,16 @@ export default createComponent({
return 'disabled';
}
if (type === 'single') {
if (Array.isArray(currentDate)) {
if (type === 'multiple') {
return this.getMultipleDayType(day);
}
if (type === 'range') {
return this.getRangeDayType(day);
}
} else if (type === 'single') {
return compareDay(day, currentDate) === 0 ? 'selected' : '';
}
if (type === 'multiple') {
return this.getMultipleDayType(day);
}
/* istanbul ignore else */
if (type === 'range') {
return this.getRangeDayType(day);
}
},
getBottomInfo(type) {

View File

@ -102,7 +102,7 @@
</demo-block>
<van-calendar
v-model="showCalendar"
v-model:show="showCalendar"
:type="type"
:color="color"
:round="round"

View File

@ -24,9 +24,9 @@ import Header from './components/Header';
export default createComponent({
props: {
show: Boolean,
title: String,
color: String,
value: Boolean,
formatter: Function,
confirmText: String,
rangePrompt: String,
@ -110,7 +110,20 @@ export default createComponent({
},
},
emits: [
'open',
'close',
'opened',
'closed',
'select',
'confirm',
'unselect',
'month-show',
'update:show',
],
data() {
this.monthRefs = [];
return {
subtitle: '',
currentDate: this.getInitialDate(),
@ -152,8 +165,8 @@ export default createComponent({
},
watch: {
show: 'init',
type: 'reset',
value: 'init',
defaultDate(val) {
this.currentDate = val;
@ -178,7 +191,7 @@ export default createComponent({
},
init() {
if (this.poppable && !this.value) {
if (this.poppable && !this.show) {
return;
}
@ -199,7 +212,7 @@ export default createComponent({
const { currentDate } = this;
const targetDate =
this.type === 'single' ? currentDate : currentDate[0];
const displayed = this.value || !this.poppable;
const displayed = this.show || !this.poppable;
/* istanbul ignore if */
if (!targetDate || !displayed) {
@ -208,8 +221,8 @@ export default createComponent({
this.months.some((month, index) => {
if (compareMonth(month, targetDate) === 0) {
const { body, months } = this.$refs;
months[index].scrollIntoView(body);
const { body } = this.$refs;
this.monthRefs[index].scrollIntoView(body);
return true;
}
@ -244,9 +257,10 @@ export default createComponent({
// calculate the position of the elements
// and find the elements that needs to be rendered
onScroll() {
const { body, months } = this.$refs;
const { body } = this.$refs;
const { months, monthRefs } = this;
const top = getScrollTop(body);
const heights = months.map((item) => item.getHeight());
const heights = months.map((item, index) => monthRefs[index].getHeight());
const heightSum = heights.reduce((a, b) => a + b, 0);
// iOS scroll bounce may exceed the range
@ -262,17 +276,17 @@ export default createComponent({
const visible = height <= bottom && height + heights[i] >= top;
if (visible && !currentMonth) {
currentMonth = months[i];
currentMonth = monthRefs[i];
}
if (!months[i].visible && visible) {
if (!monthRefs[i].visible && visible) {
this.$emit('month-show', {
date: months[i].date,
title: months[i].title,
date: monthRefs[i].date,
title: monthRefs[i].title,
});
}
months[i].visible = visible;
monthRefs[i].visible = visible;
height += heights[i];
}
@ -327,7 +341,7 @@ export default createComponent({
},
togglePopup(val) {
this.$emit('input', val);
this.$emit('update:show', val);
},
select(date, complete) {
@ -376,8 +390,9 @@ export default createComponent({
const showMonthTitle = index !== 0 || !this.showSubtitle;
return (
<Month
ref="months"
refInFor
ref={(val) => {
this.monthRefs[index] = val;
}}
date={date}
type={this.type}
color={this.color}
@ -398,10 +413,8 @@ export default createComponent({
},
genFooterContent() {
const slot = this.slots('footer');
if (slot) {
return slot;
if (this.$slots.footer) {
return this.$slots.footer();
}
if (this.showConfirm) {
@ -438,13 +451,13 @@ export default createComponent({
return (
<div class={bem()}>
<Header
v-slots={{
title: this.$slots.title,
}}
title={this.title}
showTitle={this.showTitle}
subtitle={this.subtitle}
showSubtitle={this.showSubtitle}
scopedSlots={{
title: () => this.slots('title'),
}}
firstDayOfWeek={this.dayOffset}
/>
<div ref="body" class={bem('body')} onScroll={this.onScroll}>
@ -459,23 +472,25 @@ export default createComponent({
render() {
if (this.poppable) {
const createListener = (name) => () => this.$emit(name);
const listeners = {
'onUpdate:show': this.togglePopup,
onOpen: createListener('open'),
onClose: createListener('close'),
onOpened: createListener('opened'),
onClosed: createListener('closed'),
};
return (
<Popup
round
show={this.show}
class={bem('popup')}
value={this.value}
round={this.round}
position={this.position}
closeable={this.showTitle || this.showSubtitle}
getContainer={this.getContainer}
closeOnPopstate={this.closeOnPopstate}
closeOnClickOverlay={this.closeOnClickOverlay}
onInput={this.togglePopup}
onOpen={createListener('open')}
onOpened={createListener('opened')}
onClose={createListener('close')}
onClosed={createListener('closed')}
{...listeners}
>
{this.genCalendar()}
</Popup>

View File

@ -115,10 +115,10 @@ module.exports = {
{
title: '表单组件',
items: [
// {
// path: 'calendar',
// title: 'Calendar 日历',
// },
{
path: 'calendar',
title: 'Calendar 日历',
},
// {
// path: 'checkbox',
// title: 'Checkbox 复选框',
@ -449,10 +449,10 @@ module.exports = {
{
title: 'Form Components',
items: [
// {
// path: 'calendar',
// title: 'Calendar',
// },
{
path: 'calendar',
title: 'Calendar',
},
// {
// path: 'checkbox',
// title: 'Checkbox',