VUE篇之日历组件

本文详细介绍了使用Vue编写的日历组件,包括基础版本的日期展示、增强版的上/下月日期处理、选择区间日期以及可自定义日期内容的功能实现。

1.简单日历组件展示

思路:根据当前月的第一天是星期几,来显示日期

<template>
  <div class="wrap">
    <el-button @click="preMonth">上个月</el-button>
    <el-tag>当前年份{{ curYear }}</el-tag>
    <el-tag>当前月份{{ curMonth }}</el-tag>
    <el-button @click="nextMonth">下个月</el-button>
    <div class="weeks">
      <div v-for="item in week" :key="item" class="week">{{ item }}</div>
    </div>
    <div class="days">
      <!-- 当月 -->
      <div v-for="item in curDays" :key="item + 'cur'" class="curday">{{ item }}</div>
    </div>
  </div>
</template>
<script>
import moment from 'moment';
moment.suppressDeprecationWarnings = true;
export default {
  data() {
    return {
      curYear: moment().year(), //当前年
      curMonth: moment().month() + 1, //当前月
      week: ['一', '二', '三', '四', '五', '六', '七'],
      firstDay: moment(`${moment().year()}-${moment().month() + 1}`)
        .startOf('month')
        .day(), //获取当月第一天是星期几;星期日为 0,星期六为 6
      curDays: moment().daysInMonth() //获取当月一共有多少天
    };
  },

  methods: {
    preMonth() {
      this.curMonth--;
      // 如果小于1表示上一年;重置日期
      if (this.curMonth < 1) {
        this.curYear--;
        this.curMonth = 12;
      }
      this.curDays = moment(`${this.curYear}-${this.curMonth}`).daysInMonth();
      this.firstDay = moment(`${this.curYear}-${this.curMonth}`).startOf('month').day();
      if (this.firstDay == 0) {
        this.firstDay = 7;
      }
    },
    nextMonth() {
      this.curMonth++;
      // 如果超过12表示下一年;重置日期
      if (this.curMonth > 12) {
        this.curYear++;
        this.curMonth = 1;
      }
      this.curDays = moment(`${this.curYear}-${this.curMonth}`).daysInMonth();
      this.firstDay = moment(`${this.curYear}-${this.curMonth}`).startOf('month').day();
      if (this.firstDay == 0) {
        this.firstDay = 7;
      }
    }
  }
};
</script>

<style lang="scss">
.wrap {
  width: 700px;
  height: 100%;
  .weeks {
    width: 100%;
    height: 50px;
    display: flex;
    .week {
      width: 100px;
      line-height: 50px;
      text-align: center;
      background: gainsboro;
    }
  }
  .days {
    display: flex;
    flex-wrap: wrap;
    .lastday,
    .curday {
      width: 100px;
      line-height: 50px;
      text-align: center;
    }
    .lastday {
      color: gold;
    }
  }
}
</style>

2.日历组件增强版------带有上个月或者下个月日期

较比上一版本,这个版本多了2个方法,主要用于更新上个月剩余日期,以及下个月最新日期

上个月日期:
// 获取上个月剩余天数
    getPreMonthDays() {
      if (this.firstDay == 1) return; //表示上个月无剩余天数
      let month = this.curMonth;
      let year = this.curYear;
      month--;
      if (month == 0) {
        year--;
        month = 12;
      }
      // 获取上个月的天数
      const days = moment(`${year}-${month}`).daysInMonth();
      this.preDays = days;
    },
 下个月日期:
// 获取下个月要显示的天数
    getNextMonthDays() {
      let month = this.curMonth;
      let year = this.curYear;
      // 获取当月最后一天是星期几
      const lastDay = moment(`${year}-${month}`).endOf('month').day();
      this.nextDays = lastDay == 0 ? 7 : lastDay;
    }

 整体代码:

<template>
  <div class="wrap">
    <el-button @click="preMonth">上个月</el-button>
    <el-tag>当前年份{{ curYear }}</el-tag>
    <el-tag>当前月份{{ curMonth }}</el-tag>
    <el-button @click="nextMonth">下个月</el-button>
    <div class="weeks">
      <div v-for="item in week" :key="item" class="week">{{ item }}</div>
    </div>
    <div class="days">
      <!-- 上个月 -->
      <div v-for="item in firstDay - 1" :key="item + 'pre'" class="lastday">
        {{ preDays - (firstDay - 1 - item) }}
      </div>
      <!-- 当月 -->
      <div v-for="item in curDays" :key="item + 'cur'" class="curday">{{ item }}</div>
      <!-- 下个月 -->
      <div v-for="item in 7 - nextDays" :key="item + 'next'" class="lastday">
        {{ item }}
      </div>
    </div>
  </div>
</template>
<script>
import moment from 'moment';
moment.suppressDeprecationWarnings = true;
export default {
  data() {
    return {
      preDays: 30,
      nextDays: 7,
      curYear: moment().year(), //当前年
      curMonth: moment().month() + 1, //当前月
      week: ['一', '二', '三', '四', '五', '六', '七'],
      firstDay: moment(`${moment().year()}-${moment().month() + 1}`)
        .startOf('month')
        .day(), //获取当月第一天是星期几;星期日为 0,星期六为 6
      curDays: moment().daysInMonth() //获取当月一共有多少天
    };
  },
  mounted() {
    this.getPreMonthDays();
    this.getNextMonthDays();
  },
  methods: {
    preMonth() {
      this.curMonth--;
      // 如果小于1表示上一年;重置日期
      if (this.curMonth < 1) {
        this.curYear--;
        this.curMonth = 12;
      }
      this.curDays = moment(`${this.curYear}-${this.curMonth}`).daysInMonth();
      this.firstDay = moment(`${this.curYear}-${this.curMonth}`).startOf('month').day();
      if (this.firstDay == 0) {
        this.firstDay = 7;
      }
      // 显示上个月日期
      this.getPreMonthDays();
      this.getNextMonthDays();
    },
    nextMonth() {
      this.curMonth++;
      // 如果超过12表示下一年;重置日期
      if (this.curMonth > 12) {
        this.curYear++;
        this.curMonth = 1;
      }
      this.curDays = moment(`${this.curYear}-${this.curMonth}`).daysInMonth();
      this.firstDay = moment(`${this.curYear}-${this.curMonth}`).startOf('month').day();
      if (this.firstDay == 0) {
        this.firstDay = 7;
      }
      // 显示上个月日期
      this.getPreMonthDays();
      this.getNextMonthDays();
    },
    // 获取上个月剩余天数
    getPreMonthDays() {
      if (this.firstDay == 1) return; //表示上个月无剩余天数
      let month = this.curMonth;
      let year = this.curYear;
      month--;
      if (month == 0) {
        year--;
        month = 12;
      }
      // 获取上个月的天数
      const days = moment(`${year}-${month}`).daysInMonth();
      this.preDays = days;
    },
    // 获取下个月要显示的天数
    getNextMonthDays() {
      let month = this.curMonth;
      let year = this.curYear;
      // 获取当月最后一天是星期几
      const lastDay = moment(`${year}-${month}`).endOf('month').day();
      this.nextDays = lastDay == 0 ? 7 : lastDay;
    }
  }
};
</script>

<style lang="scss">
.wrap {
  width: 700px;
  height: 100%;
  .weeks {
    width: 100%;
    height: 50px;
    display: flex;
    .week {
      width: 100px;
      line-height: 50px;
      text-align: center;
      background: gainsboro;
    }
  }
  .days {
    display: flex;
    flex-wrap: wrap;
    .lastday,
    .curday {
      width: 100px;
      line-height: 50px;
      text-align: center;
    }
    .lastday {
      color: gold;
    }
  }
}
</style>

3.日历组件增强版------可选择区间日期

思路:通过clickCount记录点击区间次数,默认是0,点击第一次是1,第二次是2;如果clickCount==2重置clickCount=0

页面渲染:通过判断日期是否在选择区间的最大和最小之间,来更改背景色

相比较之前,更新的代码:

方法新增一个点击事件

selectDate(year, day) {
      this.clickCount++;
      const date = new Date(`${year}-${this.curMonth}-${day}`);
      if (this.clickCount == 1) {
        this.startTime = date;
      } else if (this.clickCount == 2) {
        this.endTime = date;
        this.clickCount = 0;
      }
      if (this.endTime && +this.startTime > +this.endTime) {
        [this.startTime, this.endTime] = [this.endTime, this.startTime];
      }
      // console.log(
      //   this.clickCount,
      //   moment(this.startTime).format('YYYY-MM-DD'),
      //   moment(this.endTime).format('YYYY-MM-DD')
      // );
    }
  computed: {
    isSelected() {
      return (year, day) => {
        const date = new Date(`${year}-${this.curMonth}-${day}`);
        return (
          (+this.startTime <= +date && +this.endTime >= +date) || +date == +this.startTime || +date == +this.endTime
        );
      };
    }
  },

整体代码:

<template>
  <div class="wrap">
    <el-button @click="preMonth">上个月</el-button>
    <el-tag>当前年份{{ curYear }}</el-tag>
    <el-tag>当前月份{{ curMonth }}</el-tag>
    <el-button @click="nextMonth">下个月</el-button>
    <div class="weeks">
      <div v-for="item in week" :key="item" class="week">{{ item }}</div>
    </div>
    <div class="days">
      <!-- 上个月 -->
      <div
        v-for="item in firstDay - 1"
        :key="item + 'pre'"
        :class="['lastday', { select: isSelected(curYear - 1, preDays - (firstDay - 1 - item)) }]"
        @click="selectDate(curYear - 1, preDays - (firstDay - 1 - item))"
      >
        {{ preDays - (firstDay - 1 - item) }}
      </div>
      <!-- 当月 -->
      <div
        v-for="item in curDays"
        :key="item + 'cur'"
        :class="['curday', { select: isSelected(curYear, item) }]"
        @click="selectDate(curYear, item)"
      >
        {{ item }}
      </div>
      <!-- 下个月 -->
      <div
        v-for="item in 7 - nextDays"
        :key="item + 'next'"
        :class="['lastday', { select: isSelected(curYear + 1, item) }]"
        @click="selectDate(curYear + 1, item)"
      >
        {{ item }}
      </div>
    </div>
  </div>
</template>
<script>
import moment from 'moment';
moment.suppressDeprecationWarnings = true;
export default {
  data() {
    return {
      startTime: null, //记录区间开始时间
      endTime: null, //记录区间结束时间
      clickCount: 0, //用于记录点击次数
      preDays: 30, //上个月天数
      nextDays: 7, //下个月天数
      curYear: moment().year(), //当前年
      curMonth: moment().month() + 1, //当前月
      week: ['一', '二', '三', '四', '五', '六', '七'],
      firstDay: moment(`${moment().year()}-${moment().month() + 1}`)
        .startOf('month')
        .day(), //获取当月第一天是星期几;星期日为 0,星期六为 6
      curDays: moment().daysInMonth() //获取当月一共有多少天
    };
  },
  computed: {
    isSelected() {
      return (year, day) => {
        const date = new Date(`${year}-${this.curMonth}-${day}`);
        return (
          (+this.startTime <= +date && +this.endTime >= +date) || +date == +this.startTime || +date == +this.endTime
        );
      };
    }
  },
  mounted() {
    this.getPreMonthDays();
    this.getNextMonthDays();
  },
  methods: {
    preMonth() {
      this.curMonth--;
      // 如果小于1表示上一年;重置日期
      if (this.curMonth < 1) {
        this.curYear--;
        this.curMonth = 12;
      }
      this.curDays = moment(`${this.curYear}-${this.curMonth}`).daysInMonth();
      this.firstDay = moment(`${this.curYear}-${this.curMonth}`).startOf('month').day();
      if (this.firstDay == 0) {
        this.firstDay = 7;
      }
      // 显示上个月日期
      this.getPreMonthDays();
      this.getNextMonthDays();
    },
    nextMonth() {
      this.curMonth++;
      // 如果超过12表示下一年;重置日期
      if (this.curMonth > 12) {
        this.curYear++;
        this.curMonth = 1;
      }
      this.curDays = moment(`${this.curYear}-${this.curMonth}`).daysInMonth();
      this.firstDay = moment(`${this.curYear}-${this.curMonth}`).startOf('month').day();
      if (this.firstDay == 0) {
        this.firstDay = 7;
      }
      // 显示上个月日期
      this.getPreMonthDays();
      this.getNextMonthDays();
    },
    // 获取上个月剩余天数
    getPreMonthDays() {
      if (this.firstDay == 1) return; //表示上个月无剩余天数
      let month = this.curMonth;
      let year = this.curYear;
      month--;
      if (month == 0) {
        year--;
        month = 12;
      }
      // 获取上个月的天数
      const days = moment(`${year}-${month}`).daysInMonth();
      this.preDays = days;
    },
    // 获取下个月要显示的天数
    getNextMonthDays() {
      let month = this.curMonth;
      let year = this.curYear;
      // 获取当月最后一天是星期几
      const lastDay = moment(`${year}-${month}`).endOf('month').day();
      this.nextDays = lastDay == 0 ? 7 : lastDay;
    },
    selectDate(year, day) {
      this.clickCount++;
      const date = new Date(`${year}-${this.curMonth}-${day}`);
      if (this.clickCount == 1) {
        this.startTime = date;
      } else if (this.clickCount == 2) {
        this.endTime = date;
        this.clickCount = 0;
      }
      if (this.endTime && +this.startTime > +this.endTime) {
        [this.startTime, this.endTime] = [this.endTime, this.startTime];
      }
      // console.log(
      //   this.clickCount,
      //   moment(this.startTime).format('YYYY-MM-DD'),
      //   moment(this.endTime).format('YYYY-MM-DD')
      // );
    }
  }
};
</script>

<style lang="scss">
.wrap {
  width: 700px;
  height: 100%;
  .weeks {
    width: 100%;
    height: 50px;
    display: flex;
    .week {
      width: 100px;
      line-height: 50px;
      text-align: center;
      background: gainsboro;
    }
  }
  .days {
    display: flex;
    flex-wrap: wrap;
    .lastday,
    .curday {
      width: 100px;
      line-height: 50px;
      text-align: center;
      cursor: pointer;
    }
    .lastday {
      color: gold;
    }
    .select {
      background: pink;
      color: #fff;
    }
  }
}
</style>

4.日历组件增强版------可自定义日期内容

未完待续

Vue2 生态中,有多个优秀的周日历组件可以满足不同的开发需求。以下是一些推荐的组件及其特点: 1. **Vue-Calendar-Component** 这是一个轻量级、高度可定制的日历组件,支持周视图模式,适合需要灵活样式和功能扩展的项目。该组件基于 Vue2 开发,文档清晰,易于集成[^1]。可以通过自定义插槽来实现复杂的交互逻辑。 2. **Vue2-Hotel-Datepicker** 虽然该组件主要用于日期范围选择,但其周视图功能也非常强大,适合需要展示周范围的场景,例如酒店预订、日程安排等。该组件支持多种自定义选项,如禁用日期、高亮周末等[^1]。 3. **FullCalendar with Vue2 Wrapper** FullCalendar 是一个功能非常丰富的日历库,其 Vue2 的封装版本(如 `vue-fullcalendar`)支持周视图,并提供事件拖拽、资源视图等功能。适合需要复杂日程管理的项目[^1]。 4. **Vue2-Week-Calendar** 这是一个专门针对周视图设计的组件,支持横向和纵向两种布局模式,适合移动端和桌面端应用。该组件提供了事件绑定和点击回调等功能,便于集成到业务逻辑中[^1]。 5. **V-Calendar** V-Calendar 是一个功能全面的日期选择和展示组件,支持周视图、月视图等多种模式。它基于 Vue2 构建,提供了丰富的 API 和高度可定制的主题支持,适合企业级应用[^1]。 ### 示例代码 以下是一个使用 `vue-calendar-component` 的简单示例,展示如何集成周视图: ```html <template> <div> <calendar :week="true" :date.sync="selectedDate" /> <p>Selected Date: {{ selectedDate }}</p> </div> </template> <script> import { Calendar } from 'vue-calendar-component'; export default { components: { Calendar }, data() { return { selectedDate: new Date() }; } }; </script> ``` ### 特性说明 - `:week="true"`:启用周视图模式。 - `:date.sync="selectedDate"`:双向绑定当前选中的日期。 - `selectedDate`:用于存储当前选择的日期值。 ### 选择建议 - 如果项目需要轻量级且快速集成,可以选择 **Vue-Calendar-Component** 或 **Vue2-Week-Calendar**。 - 如果需要更复杂的功能(如事件拖拽、资源管理),建议使用 **FullCalendar** 的 Vue2 封装版本。 - 如果需要高度定制的主题和样式,**V-Calendar** 是一个非常不错的选择。 ---
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值