当前位置: 首页 > 工具软件 > mini calendar > 使用案例 >

`mini-ali-UI`日历组件calendar回显修改源码版:

谷弘致
2023-12-01

mini-ali-UI日历组件回显修改源码版:

  • 需求:calendar组件没有暴露出日期回显的参数,无法出现打开日历默认选择某一日期阶段,用户在点击打开日历时,默认选择了近30天的日期,用户未选择日期时,上下切换月份不清除选择的日期,用户选择日期后清除默认选择,展示用户选择的日期。经过查询,确定需要修改源码实现,以下为实现代码:
  • axml文件:几乎没有改动,可以直接使用源码
<view class="am-calendar {{className}}" a:if="{{dates.length > 0}}">
  <view class="am-calendar-months">
    <view class="am-calendar-prev-month {{prevYearDisable?'am-calendar-prev-year_disable':''}}" onTap="onPrevYearTap" a:if="{{haveYear}}">
      <view class="am-calendar-arrow am-calendar-arrow_year"></view>
    </view>
    <view class="am-calendar-prev-month  {{prevMonthDisable?'am-calendar-prev-month_disable':''}}" onTap="onPrevMonthTap">
      <am-icon type="left" class="am-calendar-arrow" />
    </view>
    <view class="am-calendar-selected-month">
      {{selectedYear}}{{_i18nYear}}{{_i18nMonth.length > 1?'':selectedMonth + 1}}{{_i18nMonth[selectedMonth]?_i18nMonth[selectedMonth]:_i18nMonth}}
    </view>
    <view class="am-calendar-next-month {{nextvMonthDisable?'am-calendar-next-month_disable':''}}" onTap="onNextMonthTap">
      <am-icon type="right" class="am-calendar-arrow" />
    </view>
    <view class="am-calendar-next-month {{nextYearDisable?'am-calendar-next-year_disable':''}}" onTap="onNextYearTap" a:if="{{haveYear}}">
      <view class="am-calendar-arrow am-calendar-arrow_year next"></view>
    </view>
  </view>

  <!-- 星期 -->

  <view class="am-calendar-days">
    <block a:for="{{[`${_i18nWeekSun}`, `${_i18nWeekMon}`, `${_i18nWeekTue}`, `${_i18nWeekWed}`, `${_i18nWeekThu}`, `${_i18nWeekFri}`, `${_i18nWeekSat}`]}}">
      <view class="am-calendar-day">{{item}}</view>
    </block>
  </view>

  <!-- 日历 -->

  <view class="am-calendar-dates">
    <block a:for="{{dates}}">
      <view class="am-calendar-week">
        <block a:for="{{item}}">
          <view class="am-calendar-date-wrap
              {{ item.isSelected ? 'am-calendar-selected': '' }}
              {{ item.isStart ? 'am-calendar-start': '' }}
              {{ item.isMiddle ? 'am-calendar-middle': '' }}
              {{ item.isEnd ? 'am-calendar-end': '' }}
              {{ item.disable ? 'am-calendar-disable': '' }}
              {{ type === 'range' ? 'is-range' : '' }}" data-year="{{item.year}}" data-month="{{item.month}}" data-date="{{item.date}}" onTap="onDateTap">
            <view class="am-calendar-block {{ blockType === 2 ? 'has-tag': '' }}"></view>
            <view class="am-calendar-date {{ item.isGray ? 'am-calendar-gray': '' }} {{ item.isToday ? 'am-calendar-today': ''}}">
              {{item.date}}
            </view>
            <view class="am-calendar-tag" style="{{
              color: item.isSelected || item.isMiddle || item.isStart || item.isEnd ? '#fff' : (item.disable ? '#ccc' : item.color)
            }}">{{item.disable ? '' : item.tag}}</view>
          </view>
        </block>
      </view>
    </block>
  </view>
</view>
  • json文件:
    • 此文件因为需要引用UI库里的iocn,不用下载该文件,直接指向原来的node_modules里就可以
{
  "component": true,
  "usingComponents": {
    "am-icon":"../../node_modules/mini-ali-ui/es/am-icon/index"
  }
}
  • js文件
    • 改动主要在该文件里,其中头部引入文件和json文件一样,指向node_modules就可以
    • 大部分方法都写了注释,还是很好读的
// import getI18n from '../_util/getI18n';
import getI18n from '../../node_modules/mini-ali-ui/es/_util/getI18n';

const i18n = getI18n().calendar;

/* eslint-disable complexity, no-param-reassign */
/* eslint max-depth: [2, 7] */
const leapYear = [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
const commonYear = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
const FIRST_MONTH = 0;
const LAST_MONTH = 11;
const DAYS_PER_ROW = 7;
const COLOR_MAP = {
  1: '#ff6010',
  2: '#00b578',
  3: '#ff8f1f',
  4: '#1677ff',
  5: '#999',
};

// 获取某月第某天是星期几
function getDay(month, year, index) {
  return new Date(year, month, index).getDay();
}

// 获取某月有几天
function getMonthLength(month, year) {
  if ((year % 400 === 0) || (year % 100 !== 0 && year % 4 === 0)) {
    return leapYear[month];
  } else {
    return commonYear[month];
  }
}

// 数字补位 1 -> 01
function prefixNum(num) {
  if (num < 10) {
    return `0${num}`;
  } else {
    return `${num}`;
  }
}

Component({
  data: {
    selectedYear: 0,
    selectedMonth: 0,
    currentDate: null,
    dates: [],
    ischeckd: false,
    blockType: 1, // 1.没有待办纯数字 2.有待办 用于区分不同类型日期块的样式。
    _i18nYear: i18n.year,
    _i18nMonth: i18n.month,
    _i18nWeekSun: i18n.sunday,
    _i18nWeekMon: i18n.monday,
    _i18nWeekTue: i18n.tuesday,
    _i18nWeekWed: i18n.wednesday,
    _i18nWeekThu: i18n.thursday,
    _i18nWeekFri: i18n.friday,
    _i18nWeekSat: i18n.saturday,
  },
  props: {
    currentDate: '',
    className: '',
    tagData: [],
    type: 'single',
    haveYear: false,
    prevMonthDisable: false,
    prevYearDisable: false,
    nextvMonthDisable: false,
    nextYearDisable: false,
    needbackdate: true, //是否需要回显日期
    needbackdateNum: '30',
  },
  didMount() {

    this.tapTimes = 1;
    const date = new Date();
    date.setHours(0);
    date.setMinutes(0);
    date.setSeconds(0);
    date.setMilliseconds(0);
    const year = date.getFullYear();
    const month = date.getMonth();

    this.setData({
      selectedYear: year,
      selectedMonth: month,
      currentDate: date,
    });

    this.refreshdates(month, year);
  },

  /**
   * 日历加载切换月份都刷新
   * */

  didUpdate() {
    if (this.data.ischeckd) {
      const {
        dates
      } = this.data;
      let blockType = 1;
      for (let i = 0; i < dates.length; i++) {
        for (let j = 0; j < dates[i].length; j++) {
          if (this.hasTag(dates[i][j])) {
            blockType = 2;
          }
        }
      }
      this.setData({
        dates,
        blockType,
      });
    } else {
      if (this.props.needbackdate) {
        let date1 = new Date();
        let date2 = new Date(date1);
        date2.setDate(date1.getDate() - this.props.needbackdateNum);
        // console.log(this.data.currentDate.getFullYear(), this.data.currentDate.getMonth(), this.data.currentDate.getDate())
        // console.log(this.props.needbackdateNum, date2.getFullYear(), date2.getMonth(), date2.getDay());
        const {
          dates
        } = this.data;
        let blockType = 1;
        for (let i = 0; i < dates.length; i++) {
          for (let j = 0; j < dates[i].length; j++) {
            if (dates[i][j].year == date2.getFullYear() || dates[i][j].year == this.data.currentDate.getFullYear()) {
              if (dates[i][j].month == date2.getMonth() || dates[i][j].month == this.data.currentDate.getMonth()) {
                if (dates[i][j].month == this.data.currentDate.getMonth() && dates[i][j].date <= this.data.currentDate.getDate()) {
                  dates[i][j].isSelected = true
                  dates[i][j].isMiddle = true
                  if (dates[i][j].date == this.data.currentDate.getDate()) {
                    dates[i][j].isSelected = true
                    dates[i][j].isMiddle = false
                  }
                }
                if (dates[i][j].month == date2.getMonth() && dates[i][j].date >= date2.getDay()) {
                  dates[i][j].isSelected = true
                  dates[i][j].isMiddle = true
                  if (dates[i][j].date == date2.getDay()) {
                    dates[i][j].isSelected = true
                    dates[i][j].isMiddle = false
                  }
                }
              }
            }
            if (this.hasTag(dates[i][j])) {
              blockType = 2;
            }
          }
        }
        this.setData({
          dates,
          blockType,
        });
      }
    }

  },
  methods: {

    /**
     * 点击上一年按钮
     * */

    onPrevYearTap() {
      const {
        selectedMonth,
        selectedYear
      } = this.data;
      const {
        prevYearDisable
      } = this.props;

      if (!prevYearDisable) {
        let year = selectedYear;
        const month = selectedMonth;

        year = selectedYear - 1;

        if (this.props.onYearChange) {
          this.props.onYearChange(year, selectedYear);
        }

        if (this.props.onChange) {
          this.props.onChange({
            year,
            month
          }, {
            year: selectedYear,
            month: selectedMonth
          });
        }

        this.setData({
          selectedYear: year,
        });

        this.refreshdates(month, year);
      }
    },

    /**
     * 点击下一年按钮
     * */

    onNextYearTap() {
      const {
        selectedMonth,
        selectedYear
      } = this.data;
      const {
        nextYearDisable
      } = this.props;

      if (!nextYearDisable) {
        let year = selectedYear;
        const month = selectedMonth;

        year = selectedYear + 1;

        if (this.props.onYearChange) {
          this.props.onYearChange(year, selectedYear);
        }

        if (this.props.onChange) {
          this.props.onChange({
            year,
            month
          }, {
            year: selectedYear,
            month: selectedMonth
          });
        }

        this.setData({
          selectedYear: year,
        });

        this.refreshdates(month, year);
      }
    },

    /**
     * 点击上一月按钮
     * */

    onPrevMonthTap() {
      const {
        selectedMonth,
        selectedYear
      } = this.data;
      const {
        prevMonthDisable
      } = this.props;

      if (!prevMonthDisable) {
        let year = selectedYear;
        let month = selectedMonth;
        // 如果当前选中是一月份,前一月是去年的12月
        if (selectedMonth === FIRST_MONTH) {
          year = selectedYear - 1;
          month = LAST_MONTH;
        } else {
          month = selectedMonth - 1;
        }

        if (this.props.onMonthChange) {
          this.props.onMonthChange(month, selectedMonth);
        }

        if (this.props.onChange) {
          this.props.onChange({
            year,
            month
          }, {
            year: selectedYear,
            month: selectedMonth
          });
        }

        this.setData({
          selectedYear: year,
          selectedMonth: month,
        });

        this.refreshdates(month, year);
      }
    },

    /**
     * 点击下一月按钮
     * */

    onNextMonthTap() {
      const {
        selectedMonth,
        selectedYear
      } = this.data;
      const {
        nextvMonthDisable
      } = this.props;

      if (!nextvMonthDisable) {
        let year = selectedYear;
        let month = selectedMonth;
        // 如果当前选中是十二月份,下一月是去年的12月
        if (selectedMonth === LAST_MONTH) {
          year = selectedYear + 1;
          month = FIRST_MONTH;
        } else {
          month = selectedMonth + 1;
        }

        if (this.props.onMonthChange) {
          this.props.onMonthChange(month, selectedMonth);
        }

        if (this.props.onChange) {
          this.props.onChange({
            year,
            month
          }, {
            year: selectedYear,
            month: selectedMonth
          });
        }

        this.setData({
          selectedYear: year,
          selectedMonth: month,
        });

        this.refreshdates(month, year);
      }
    },

    /**
     * 非点击事件,待逆向测试
     * */

    refreshdates(month, year) {
      this.tapTimes = 1;
      const {
        selectedYear,
        selectedMonth,
        currentDate
      } = this.data;
      const firstDay = getDay(month, year, 1);
      const days = getMonthLength(month, year);
      const datesArray = [];
      const currentDateTimeStamp = +currentDate;
      let num = 0;

      for (let i = 0; i < firstDay; i++) {
        num += 1;
        // 如果当前选中的是一月份,前一个月是去年的12月
        let _year = selectedYear;
        let _month = selectedMonth;

        if (selectedMonth === 0) {
          _year = selectedYear - 1;
          _month = LAST_MONTH;
        } else {
          _year = selectedYear;
          _month = selectedMonth - 1;
        }

        const date = getMonthLength(_month, _year) - i;
        datesArray.unshift({
          year: _year,
          month: _month,
          date,
          isToday: false,
          isGray: true,
          isSelected: false,
          tag: '',
        });
      }

      for (let i = 0; i < days; i++) {
        num += 1;
        const date = i + 1;
        const dateTimeStamp = +new Date(selectedYear, selectedMonth, date);
        datesArray.push({
          year: selectedYear,
          month: selectedMonth,
          date,
          isToday: dateTimeStamp === currentDateTimeStamp,
          isGray: false,
          isSelected: dateTimeStamp === currentDateTimeStamp,
          tag: '',
        });
      }

      let nextDate = 0;
      let daysPerPage = 35;

      if (num > 35) {
        daysPerPage = 42;
      }

      for (let i = 0; i < daysPerPage - days - firstDay; i++) {
        // 如果是12月,下月是第二年的1月份
        nextDate += 1;
        let _year = selectedYear;
        let _month = selectedMonth;

        if (selectedMonth === LAST_MONTH) {
          _year = selectedYear + 1;
          _month = FIRST_MONTH;
        } else {
          _year = selectedYear;
          _month = selectedMonth + 1;
        }

        datesArray.push({
          year: _year,
          month: _month,
          date: nextDate,
          isToday: false,
          isGray: true,
          isSelected: false,
          tag: '',
        });
      }
      let blockType = 1;
      for (let i = 0; i < datesArray.length; i++) {
        if (this.hasTag(datesArray[i])) {
          blockType = 2;
        }
      }

      const dates = [];
      let weekDates = [];
      for (let i = 0; i < datesArray.length; i++) {
        weekDates.push(datesArray[i]);
        if ((i + 1) % DAYS_PER_ROW === 0) {
          dates.push([...weekDates]);
          weekDates = [];
        }
      }

      this.setData({
        dates,
        blockType,
      });
    },

    /**
     * 检查是否有tag并循环
     * */

    hasTag(dateObj) {
      const {
        tagData
      } = this.props;
      // 去重由调用者处理
      if (tagData.length === 0) {
        dateObj.tag = '';
        return false;
      }
      return tagData.some((item) => {
        const dateArr = item.date.split('-');
        const dateStr = [];
        // 兼容ios下new Date('2018-1-1')格式返回invalid Date的问题
        for (let i = 0; i < dateArr.length; i++) {
          dateStr.push(dateArr[i].length > 1 ? dateArr[i] : `0${dateArr[i]}`);
        }

        const date = new Date(dateStr.join('-'));
        if (dateObj.year === date.getFullYear() &&
          dateObj.month === date.getMonth() &&
          dateObj.date === date.getDate()) {
          dateObj.tag = item.tag;
          dateObj.color = COLOR_MAP[item.tagColor];
          dateObj.disable = item.disable;
          return true;
        } else {
          dateObj.tag = '';
          return false;
        }
      });
    },

    /**
     * 选择日期区间
     * */

    getDateGap(day1, day2) {
      const date1 = +new Date(day1.year, prefixNum(day1.month), prefixNum(day1.date));
      const date2 = +new Date(day2.year, prefixNum(day2.month), prefixNum(day2.date));
      return (date1 - date2) / (24 * 3600 * 1000);

    },

    /**
     * 生成日期格式
     * 用户点击后
     * */

    makeDate(dateObj) {

      /**
       * 记录用户是否选择了日期,
       * 判断展示默认回显还是不显示
       * */

      this.setData({
        ischeckd: true
      })
      return new Date(`${dateObj.year}-${prefixNum(dateObj.month + 1)}-${prefixNum(dateObj.date)}`);

    },

    /**
     * 日历点击事件
     * */

    onDateTap(event) {
      const {
        dates
      } = this.data;
      const {
        year,
        month,
        date
      } = event.currentTarget.dataset;
      const {
        type
      } = this.props;

      if (type === 'range') {
        if (this.tapTimes % 2 === 0) {
          this.tapTimes += 1;
          this.endDate = {
            year,
            month,
            date
          };
          const dateGap = this.getDateGap(this.startDate, this.endDate);
          if (dateGap > 0) {
            [this.startDate, this.endDate] = [this.endDate, this.startDate];
          }

          let hasDisable = false;
          for (let i = 0; i < dates.length; i++) {
            for (let j = 0; j < dates[i].length; j++) {
              const dateObj = dates[i][j];
              dateObj.isStart = false;
              dateObj.isMiddle = false;
              dateObj.isEnd = false;
              const startDateGap = this.getDateGap(dateObj, this.startDate);
              const endDateGap = this.getDateGap(dateObj, this.endDate);
              if (dateObj.year === year && dateObj.month === month && dateObj.date === date && dateObj.disable) {
                hasDisable = true;
              }
              if (startDateGap > 0 && endDateGap < 0) {
                if (dateObj.disable) {
                  hasDisable = true;
                }

                if (dateGap !== 0) {
                  if (j === 0) {
                    dateObj.isStart = true;
                  } else if (j === 6) {
                    dateObj.isEnd = true;
                  } else {
                    dateObj.isMiddle = true;
                  }
                } else {
                  dateObj.isSelected = true;
                }
              }

              if (this.startDate.year === dateObj.year &&
                this.startDate.month === dateObj.month &&
                this.startDate.date === dateObj.date && dateGap !== 0) {
                if (j === 6) {
                  dateObj.isSelected = true;
                } else {
                  dateObj.isStart = true;
                }
              }

              if (this.endDate.year === dateObj.year &&
                this.endDate.month === dateObj.month &&
                this.endDate.date === dateObj.date && dateGap !== 0) {
                if (j === 0) {
                  dateObj.isSelected = true;
                } else {
                  dateObj.isEnd = true;
                }
              }
            }
          }
          if (hasDisable) {
            this.props.onSelectHasDisableDate([this.makeDate(this.startDate), this.makeDate(this.endDate)]);
            return;
          }

          if (this.props.onSelect) {
            this.props.onSelect([this.makeDate(this.startDate), this.makeDate(this.endDate)]);
          }
        } else {
          let isDisable = false;
          for (let i = 0; i < dates.length; i++) {
            for (let j = 0; j < dates[i].length; j++) {
              const dateObj = dates[i][j];
              if (dateObj.year === year && dateObj.month === month && dateObj.date === date) {
                if (dateObj.disable) {
                  isDisable = true;
                  dateObj.isSelected = false;
                } else {
                  dateObj.isSelected = true;
                }
                dateObj.isStart = false;
                dateObj.isMiddle = false;
                dateObj.isEnd = false;
              } else {
                dateObj.isSelected = false;
                dateObj.isStart = false;
                dateObj.isMiddle = false;
                dateObj.isEnd = false;
              }
            }
          }
          if (!isDisable) {
            this.tapTimes += 1;
          }
          this.startDate = {
            year,
            month,
            date
          };
        }

        this.setData({
          dates,
        });
      } else {
        let isDisable = false;
        for (let i = 0; i < dates.length; i++) {
          for (let j = 0; j < dates[i].length; j++) {
            const dateObj = dates[i][j];
            if (dateObj.year === year && dateObj.month === month && dateObj.date === date) {
              dateObj.isSelected = true;
              if (dateObj.disable) {
                isDisable = true;
              }
            } else {
              dateObj.isSelected = false;
            }
          }
        }

        if (isDisable) {
          return;
        }

        this.setData({
          dates,
        });

        if (this.props.onSelect) {
          this.props.onSelect([this.makeDate({
            year,
            month,
            date
          }), undefined]);
        }
      }
    },
  },
});

使用

  • 使用方法和普通组件一样,唯一一点区别就是我没有修改样式组件,因为源码组件样式是用less写的,有点错综复杂,代价太大,于是在引用这个组件时,需要json文件中在组件库里引用原组件,就可以自动识别它的样式了。

    • 举例:

    • {
          "defaultTitle": "日历测试页面",
          "titleBarColor":"#fff",
          "pullRefresh": true,
          "usingComponents": {
              "calendar": "mini-ali-ui/es/calendar/index",	//原组件日历
              "calendar-local": "../../Component/calendar/calendar"	//修改后的日历组件
          }
        }
      

添加的属性

属性类型描述
needbackdateBoolean是否展示回显30日,默认为false
 类似资料: