# Calendar 日历

### 引入

在`index.config.js中引入组件

```json
"usingComponents": {
  "van-calendar": "@vant/weapp/calendar/index",
  "van-cell": "../../vant/cell/index"
}
```

## 代码演示

### 选择单个日期

下面演示了结合单元格来使用日历组件的用法，日期选择完成后会触发`confirm`事件

```html
     <View>
        <demo-block title="基础用法">
          <van-cell
            is-link
            title="选择单个日期"
            data-type="single"
            data-id="selectSingle"
            value={ computed.formatFullDate(this.state.date.selectSingle) }
            onClick={(e)=>this.show(e)}
          />

          <van-cell
            is-link
            title="选择多个日期"
            data-type="multiple"
            data-id="selectMultiple"
            value={ computed.formatMultiple(this.state.date.selectMultiple) }
            onClick={(e)=>this.show(e)}
          />

          <van-cell
            is-link
            title="选择日期区间"
            data-type="range"
            data-id="selectRange"
            value={ computed.formatRange(this.state.date.selectRange) }
            onClick={(e)=>this.show(e)}
          />
        </demo-block>

        <demo-block title="快捷选择">
          <van-cell
            is-link
            title="选择单个日期"
            data-type="single"
            data-id="quickSelect1"
            value={ computed.formatFullDate(this.state.date.quickSelect1) }
            onClick={(e)=>this.show(e)}
          />

          <van-cell
            is-link
            title="选择日期区间"
            data-type="range"
            data-id="quickSelect2"
            value={ computed.formatRange(this.state.date.quickSelect2) }
            onClick={(e)=>this.show(e)}
          />
        </demo-block>

        <demo-block title="自定义日历">
          <van-cell
            is-link
            title="自定义颜色"
            data-type="range"
            data-id="customColor"
            value={ computed.formatRange(this.state.date.customColor) }
            onClick={(e)=>this.show(e)}
          />

          <van-cell
            is-link
            title="自定义日期范围"
            data-type="single"
            data-id="customRange"
            value={ computed.formatFullDate(this.state.date.customRange) }
            onClick={(e)=>this.show(e)}
          />

          <van-cell
            is-link
            title="自定义按钮文字"
            data-type="range"
            data-id="customConfirm"
            value={ computed.formatRange(this.state.date.customConfirm) }
            onClick={(e)=>this.show(e)}
          />

          <van-cell
            is-link
            title="自定义日期文案"
            data-type="range"
            data-id="customDayText"
            value={ computed.formatRange(this.state.date.customDayText) }
            onClick={(e)=>this.show(e)}
          />

          <van-cell
            is-link
            title="自定义弹出位置"
            data-type="single"
            data-id="customPosition"
            value={computed.formatFullDate(this.state.date.customPosition) }
            onClick={(e)=>this.show(e)}
          />

          <van-cell
            is-link
            title="日期区间最大范围"
            data-type="range"
            data-id="maxRange"
            value={ computed.formatRange(this.state.date.maxRange) }
            onClick={(e)=>this.show(e)}
          />
        </demo-block>



        <van-calendar
          show={this.state.showCalendar}
          type={this.state.type}
          color={this.state.color}
          round={this.state.round}
          position={this.state.position}
          minDate={this.state.minDate}
          maxDate={this.state.maxDate}
          maxRange={this.state.maxRange}
          formatter={this.state.formatter}
          showConfirm={this.state.showConfirm}
          confirmText={this.state.confirmText}
          confirmDisabledText={this.state.confirmDisabledText}
          onConfirm={(e)=>this.onConfirm(e)}
          onSelect={(e)=>this.onSelect(e)}
          onUnselect={(e)=>this.onUnselect(e)}
          onOpen={()=>this.onOpen()}
          onOpened={()=>this.onOpened()}
          onClose={()=>this.onClose()}
          onClosed={()=>this.onClosed()}
        >
        </van-calendar>
      </View>
```

```js
class CalendarComponents extends Component {
  constructor(props) {
    super(props)
  };



  state = {
    date: {
      maxRange: [],
      selectSingle: null,
      selectRange: [],
      selectMultiple: [],
      quickSelect1: null,
      quickSelect2: [],
      customColor: [],
      customConfirm: [],
      customRange: null,
      customDayText: [],
      customPosition: null
    },
    id:'selectSingle',
    type: 'single',
    round: true,
    color: undefined,
    minDate: Date.now(),
    maxDate: new Date(
      new Date().getFullYear(),
      new Date().getMonth() + 6,
      new Date().getDate()
    ).getTime(),
    maxRange: undefined,
    position: undefined,
    formatter: undefined,
    showConfirm: false,
    showCalendar: false,
    tiledMinDate: new Date(2012, 0, 10).getTime(),
    tiledMaxDate: new Date(2012, 2, 20).getTime(),
    confirmText: undefined,
    confirmDisabledText: undefined
  };

  componentWillMount() {

  }

  //onShow
  componentDidShow() {

  }

  onConfirm(event) {
    console.log(event);
    this.setState({ showCalendar: false });
    let res=this.state.date;
    res[this.state.id]=event.detail;
    this.setState({
      date: res
    });
    debugger
  }

  onSelect(event) {
    console.log(event);
  }

  onUnselect(event) {
    console.log(event);
  }

  onClose() {
    this.setState({ showCalendar: false });
  }

  onOpen() {
    console.log('open');
  }

  onOpened() {
    console.log('opened');
  }

  onClosed() {
    console.log('closed');
  }

  resetSettings() {
    this.setState({
      round: true,
      color: null,
      minDate: Date.now(),
      maxDate: new Date(
        new Date().getFullYear(),
        new Date().getMonth() + 6,
        new Date().getDate()
      ).getTime(),
      maxRange: null,
      position: 'bottom',
      formatter: null,
      showConfirm: true,
      confirmText: '确定',
      confirmDisabledText: null
    });
  }

  show(event) {
    this.resetSettings();
    const { type, id } = event.currentTarget.dataset;
    const data = {
      id,
      type,
      showCalendar: true
    }

    switch (id) {
      case 'quickSelect1':
      case 'quickSelect2':
        data.showConfirm = false;
        break;
      case 'customColor':
        data.color = '#07c160';
        break;
      case 'customConfirm':
        data.confirmText = '完成';
        data.confirmDisabledText = '请选择结束时间';
        break;
      case 'customRange':
        data.minDate = new Date(2010, 0, 1).getTime();
        data.maxDate = new Date(2010, 0, 31).getTime();
        break;
      case 'customDayText':
        data.minDate = new Date(2010, 4, 1).getTime();
        data.maxDate = new Date(2010, 4, 31).getTime();
        data.formatter = this.dayFormatter;
        break;
      case 'customPosition':
        data.round = false;
        data.position = 'right';
        break;
      case 'maxRange':
        data.maxRange = 3;
        break;
    }
    this.setState({...data});
  }

  dayFormatter(day) {
    const month = day.date.getMonth() + 1;
    const date = day.date.getDate();

    if (month === 5) {
      if (date === 1) {
        day.topInfo = '劳动节';
      } else if (date === 4) {
        day.topInfo = '五四青年节';
      } else if (date === 11) {
        day.text = '今天';
      }
    }

    if (day.type === 'start') {
      day.bottomInfo = '入店';
    } else if (day.type === 'end') {
      day.bottomInfo = '离店';
    }

    return day;
  }
}
```

## API
### 注:属性应用在组件上需要统一使用驼峰式命名，如custom-class应变为
```html
<van-button type="primary" customClass='myClass' size="large">大号按钮</van-button>
```
### 注:事件应用在组件上需要统一使用驼峰式命名，如bind:click/bind:search/bind:before-enter应变为
```html
<van-button type="primary" onClick={()=>this.onClick()}>大号按钮</van-button>
<van-search type="primary" onSearch={()=>this.onSearch()}>大号按钮</van-search>
<van-transition type="primary" onBeforeEnter={()=>this.onBeforeEnter()}>大号按钮</van-transition>
```
### Props

| 参数 | 说明 | 类型 | 默认值 |
| --- | --- | --- | --- |
| type | 选择类型:<br>`single`表示选择单个日期，<br>`multiple`表示选择多个日期，<br>`range`表示选择日期区间 | _string_ | `single` |
| title | 日历标题 | _string_ | `日期选择` |
| color | 主题色，对底部按钮和选中日期生效 | _string_ | `#ee0a24` |
| min-date | 可选择的最小日期 | _number_ | 当前日期 |
| max-date | 可选择的最大日期 | _number_ | 当前日期的六个月后 |
| default-date | 默认选中的日期，`type`为`multiple`或`range`时为数组 | _number \| number[]_ | 今天 |
| row-height | 日期行高 | _number \| string_ | `64` |
| formatter | 日期格式化函数 | _(day: Day) => Day_ | - |
| poppable | 是否以弹层的形式展示日历 | _boolean_ | `true` |
| show-mark | 是否显示月份背景水印 | _boolean_ | `true` |
| show-title | 是否展示日历标题 | _boolean_ | `true` |
| show-subtitle | 是否展示日历副标题（年月） | _boolean_ | `true` |
| show-confirm | 是否展示确认按钮 | _boolean_ | `true` |
| confirm-text | 确认按钮的文字 | _string_ | `确定` |
| confirm-disabled-text | 确认按钮处于禁用状态时的文字 | _string_ | `确定` |

### Poppable Props

当 Canlendar 的 `poppable` 为 `true` 时，支持以下 props:

| 参数 | 说明 | 类型 | 默认值 |
| --- | --- | --- | --- |
| show | 是否显示日历弹窗 | _boolean_ | `false` |
| position | 弹出位置，可选值为 `top` `right` `left` | _string_ | `bottom` |
| round | 是否显示圆角弹窗 | _boolean_ | `true` |
| close-on-click-overlay | 是否在点击遮罩层后关闭 | _boolean_ | `true` |
| safe-area-inset-bottom | 是否开启底部安全区适配 | _boolean_ | `true` |

### Range Props

当 Canlendar 的 `type` 为 `range` 时，支持以下 props:

| 参数 | 说明 | 类型 | 默认值 |
| --- | --- | --- | --- |
| max-range | 日期区间最多可选天数，默认无限制 | _number \| string_ | - |
| range-prompt | 范围选择超过最多可选天数时的提示文案 | _string_ | `选择天数不能超过 xx 天` |
| allow-same-day | 是否允许日期范围的起止时间为同一天 | _boolean_ | `fasle` |

### Day 数据结构

日历中的每个日期都对应一个 Day 对象，通过`formatter`属性可以自定义 Day 对象的内容

| 键名 | 说明 | 类型 |
| --- | --- | --- |
| date | 日期对应的 Date 对象 | _Date_ |
| type | 日期类型，可选值为`selected`、`start`、`middle`、`end`、`disabled` | _string_ |
| text | 中间显示的文字 | _string_ |
| topInfo | 上方的提示信息 | _string_ |
| bottomInfo | 下方的提示信息 | _string_ |

### Events

| 事件名 | 说明 | 回调参数 |
| --- | --- | --- |
| select | 点击任意日期时触发 | _value: Date \| Date[]_ |
| unselect | 当 Canlendar 的 `type` 为 `multiple` 时,点击已选中的日期时触发 | _value: Date_ |
| confirm | 日期选择完成后触发，若`show-confirm`为`true`，则点击确认按钮后触发 | _value: Date \| Date[]_ |
| open | 打开弹出层时触发 | - |
| close | 关闭弹出层时触发 | - |
| opened | 打开弹出层且动画结束后触发 | - |
| closed | 关闭弹出层且动画结束后触发 | - |

### Slots

| 名称   | 说明               |
| ------ | ------------------ |
| title  | 自定义标题         |
| footer | 自定义底部区域内容 |

### 方法

通过 selectComponent 可以获取到 Calendar 实例并调用实例方法

| 方法名 | 说明                   | 参数 | 返回值 |
| ------ | ---------------------- | ---- | ------ |
| reset  | 重置选中的日期到默认值 | -    | -      |
