ant Disign Vue 日历组件

本文详细介绍了如何使用antDesignVue库中的a-calendar组件进行封装,包括自定义头部、日期单元格和提示框,以及处理日期面板变化和选择日期的事件逻辑。
摘要由CSDN通过智能技术生成

基于ant Design Vue日历组件a-calendar封装的日历组件

示例

 结构

<month-calendar :date="dateStr" :data="workData" @panelChange="onPanelChange">
  <template v-slot:header="{ date }">
    <div class="calendar-header">
      <a-month-picker :value="date" :allow-clear="false" @change="onPanelChange"></a-month-picker>
      <div>其他内容呀</div>
    </div>
  </template>
  <template v-slot:dateCell="{ item }">
    <div class="calendar-data">
      <div v-if="item.todaySummary" class="calendar-data__text">{{ item.todaySummary }}</div>
    </div>
  </template>
  <template v-slot:dateTooltip="{ item }">
    <div v-if="item.todaySummary" class="popover-content">{{ item.todaySummary }}</div>
  </template>
</month-calendar>

逻辑

import MonthCalendar from './modules/monthCalendar.vue';
import moment from 'moment';
export default {
  name: 'Test',
  components: {
    MonthCalendar
  },
  data() {
    return {
      date: moment(),
      workData: {}
    }
  },
  computed: {
    dateStr() {
      return this.date.format('YYYY-MM-DD');
    }
  },
  created() {
    this.queryMonth();
  },
  methods: {
    queryMonth() {
      const month = this.date.format('YYYY-MM');
      const workData = {
        [`${month}-12`]: {tooltip: true, todaySummary: '123'},
        [`${month}-13`]: {tooltip: true, todaySummary: '工作内容'},
        [`${month}-15`]: {tooltip: true, todaySummary: '广袤星河里亿万生命,何其有幸,与你一同在场,就在,这里。'},
        [`${month}-16`]: {tooltip: true, todaySummary: '从每一个寻寻觅觅的日子里,穿行而过,看似捕手的,可能也是猎物,看似平常的,可能正是宝藏。灵魂触角,敏感或是迟钝,都有权尽情舞蹈,大千世界啊,风马牛秘密联络,肉眼所得,仅供参考。'},
        [`${month}-18`]: {tooltip: true, todaySummary: '过去,当下,未来,未必真有界限,时间,只是行一个方便的幻觉。所以,无忧无惧,专心游戏,无牵无挂,寻宝之旅。'},
        [`${month}-21`]: {tooltip: true, todaySummary: '常见的一个定义是:“材料是提供文章内容和表达主题的事物和观念。”严格地说,“事物”并不是材料:尚未反映到头脑中的“事物”不会是材料;已经反映到头脑中(或写入文章中)的“事物”,已是一种观念,一种关于“事物”的感性或理性的认识。这是唯物论的常识。与此相一致,人们有“文章是客观事物的反映”的正确命题:“反映”二字,不独指文章的观点,也指其中的材料。也正因为如此,人们评价文中材料时才有“真与假”、“片面与全面”等标准。如果材料的外延包含与“观念”相对的“事物”本身,那材料(事物)就没有“真假”、“偏全”等区别了。所以,材料是“事物”的说法不能成立'},
      };
      this.workData = Object.freeze(workData);
      console.log(workData);
    },
    onPanelChange(value) {
      // 日期变化
      this.date = value;
      this.queryMonth();
    }
  }
}

样式

@font-df: 0.14rem;
.calendar-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
}
.calendar-data {
  min-height: calc(@font-df * 1.6 * 4 + 0.2rem);  // 4行 + padding-bottom
  padding: 0 0.2rem 0.4rem;
  &__text {
    display: -webkit-box !important;
    overflow: hidden;
    text-overflow: ellipsis;
    -webkit-box-orient: vertical !important;
    word-break: break-all;
    -webkit-line-clamp: 3;	/* 两行 */
    line-height: 1.4em;			/* 行高 */
    max-height: 4.2em;  		/* 1.4 * 2 */
  }
}
.popover-content {
  max-width: 500px;
  white-space: pre-wrap;
}

API

attributes

events

事件名说明参数

panelChange

日期面板变化回调

data:moment, mode: string

select

点击选择日期回调

data:moment

scoped slot

插槽名说明

header

自定义头部,参数:{date}
dateCell自定义日期单元格,参数:{item}
dateTooltip自定义tooptip,参数:{item}

组件代码

结构、逻辑

import moment from 'moment';
export default {
  name: 'MonthCalendar',
  props: {
    date: {
      // 查询日期
      type: String,
      default: ''
    },
    format: {
      // 日期格式
      type: String,
      default: 'YYYY-MM-DD'
    },
    data: {
      type: Object,
      default: () => ({})
    },
    defaultProps: {
      type: Object,
      default: () => ({ tooltip: 'tooltip' }),
    }
  },
  computed: {
    dutyDate() {
      if (this.date) {
        const date = moment(this.date, this.format);
        if (date.isValid()) {
          return date;
        }
      }
      // date 没传日期或传递日期格式错误 默认今天
      const today = moment();
      return today;
    },
    validRange() {
      // 可以显示的日期 对应月份
      let date = moment(this.dutyDate);
      const start = date.startOf('month'); // 会修改原始值
      date = moment(this.dutyDate);
      const end = date.endOf('month');
      return [start, end];
    },
    todayDate() {
      // 今天
      return moment(moment().format('YYYY-MM-DD'));
    },
    tooltipKey() {
      return this.defaultProps.tooltip || 'tooltip';
    }
  },
  methods: {
    headerRender() {
      // 自定义头部内容
      if (this.$scopedSlots.header) {
        // 处理作用域插槽 header
        return (this.$scopedSlots.header({ date: this.dutyDate }));
      }
      return (<div class="fullcalendar-header">
        <a-month-picker
          value={this.dutyDate}
          allowClear={false}
          onChange={this.onChangeMonth}
        ></a-month-picker>
      </div>);
    },
    onChangeMonth(date, dateString) {
      // 选择日期发生变化
      this.$emit('panelChange', date, 'month');
    },
    onPanelChange(value, mode) {
      // 日期面板变化回调
      this.$emit('panelChange', value, mode);
    },
    onSelect(date) {
      // 点击选择日期回调
      this.$emit('select', date);
    }
  },
  render(h) {
    let lastDay = this.validRange[1].day(); // 星期几(星期日为 0, 星期六为 6)
    if (lastDay === 0) lastDay = 7;         // 当月最后一天是星期几 1-7
    const last = moment(this.validRange[1]).add((7 - lastDay), 'days'); // 显示的最后一天 (显示从星期一开始)
    const dateFullCellRender = (value) => {
      // 作用域插槽 dateFullCellRender
      if (value.isAfter(last)) {
        // 最后一行 不渲染
        return null;
      }
      const day = value.date();
      const date = value.format(this.format);
      let item = {}, itemHas = false;
      if (this.data[date]) {
        item = this.data[date];
        itemHas = true;
      }
      const isSameMonth = (value.isAfter(this.validRange[0]) || value.isSame(this.validRange[0])) && value.isBefore(this.validRange[1]);  // 本月
      const isSameDay = this.todayDate.isSame(value);  // 当天
      const dateFullCell = (<div class='fullcalendar-date'>
        <div class='fullcalendar-value'>
          <span class={[isSameMonth ? 'is-same-month' : '', isSameDay ? 'is-same-day' : '']}>{day}</span>
        </div>
        {/* 处理作用域插槽 dateCell */}
        {this.$scopedSlots.dateCell
          ?
          this.$scopedSlots.dateCell({ item: item })
          :
          <div class="fullcalendar-content">
            {itemHas ? (<a-icon type="calendar" theme="twoTone" style="font-size: 36px;" />) : ''}
          </div>
        }
      </div>);
      return (<div class="fullcalendar-date-wrap">
        {/* 处理作用域插槽 dateTooltip */}
        {(this.$scopedSlots.dateTooltip && !!item[this.tooltipKey])
          ?
          (<a-popover title={date}>
            <template slot="content">{this.$scopedSlots.dateTooltip({ item: item })}</template>
            {dateFullCell}
          </a-popover>)
          :
          dateFullCell
        }
      </div>);
    }
    return (
      // validRange={this.validRange}
      <a-calendar
        value={this.dutyDate}
        headerRender={this.headerRender}
        class="month-calendar"
        scopedSlots={{ dateFullCellRender }}
        onPanelChange={this.onPanelChange}
        onSelect={this.onSelect}
      >
      </a-calendar>
    );
  }
}

样式

@primaryColor: #1890FF;
@primaryLight: #F2F8FD;
@tableBorderColor: #EBEEEF;
@white: #FFFFFF;

@font-lg: 0.16rem;
@font-df: 0.14rem;

@fontColor: #333333;
@fontLight: #999999;
@fontDisabled: #DDDDDD;

.month-calendar {
  /deep/ .ant-fullcalendar-calendar-body {
    padding-left: 0;
    padding-right: 0;
  }
  /deep/ table {
    border-collapse: collapse;
    thead {
      font-size: @font-lg;
      color: @fontLight;
      font-weight: 400;
      th {
        padding-right: 12px;
        padding-bottom: 13px;
      }
    }
    tbody {
      border-top: 1px solid @tableBorderColor;
      border-left: 1px solid @tableBorderColor;
    }
    td {
      border-bottom: 1px solid @tableBorderColor;
      border-right: 1px solid @tableBorderColor;
      vertical-align: top;
      &:empty {
        // 最后一行 不渲染 (空元素 隐藏边框)
        border: unset;
      }
    }
  }
  .fullcalendar-date-wrap {
    height: 100%;
  }
  .fullcalendar-date {
    height: 100%;
    &:hover {
      background: @primaryLight;
      // cursor: pointer;
    }
    .fullcalendar-value {
      padding: 0.08rem;
      text-align: right;
      & > span {
        width: 0.32rem;
        height: 0.32rem;
        line-height: 0.32rem;
        text-align: center;
        display: inline-block;
        font-size: @font-lg;
        font-weight: bold;
        color: @fontDisabled;
        &.is-same-month {
          color: @fontColor;
        }
        &.is-same-day {
          background-color: @primaryColor;
          color: @white;
          border-radius: 50%;
        }
      }
    }
    .fullcalendar-content {
      min-height: calc(@font-df * 1.6 * 4 + 0.2rem);  // 4行 + padding-bottom
      padding: 0 0.2rem 0.4rem;
      display: flex;
      justify-content: center;
      align-items: center;
    }
  }
  .fullcalendar-header {
    padding: 11px 16px 11px 0;
    display: flex;
    justify-content: flex-end;
  }
}

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值