mirror of
https://gitee.com/vant-contrib/vant.git
synced 2025-04-06 03:57:59 +08:00
feat: migrate Calendar component
This commit is contained in:
parent
a6888944ea
commit
0dd713f361
@ -46,4 +46,5 @@ module.exports = [
|
||||
'picker',
|
||||
'dialog',
|
||||
'toast',
|
||||
'calendar',
|
||||
];
|
||||
|
@ -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`
|
||||
|
||||
|
@ -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 position,can 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` |
|
||||
|
@ -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` |
|
||||
|
@ -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>;
|
||||
}
|
||||
},
|
||||
|
@ -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) {
|
||||
|
@ -102,7 +102,7 @@
|
||||
</demo-block>
|
||||
|
||||
<van-calendar
|
||||
v-model="showCalendar"
|
||||
v-model:show="showCalendar"
|
||||
:type="type"
|
||||
:color="color"
|
||||
:round="round"
|
||||
|
@ -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>
|
||||
|
@ -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',
|
||||
|
Loading…
x
Reference in New Issue
Block a user