基于vue手动实现一个日历组件

 更新时间:2024年01月24日 15:21:05   作者:通往自由之路  
这篇文章主要为大家详细介绍了如何基于vue手动实现一个日历组件,文中的示例代码讲解详细,具有一定的借鉴价值,有需要的小伙伴可以跟随小编一起学习一下

最近需要一个日历,当前能用的现成的组件库也有日历组件,但因为不满足需求,所以决定自己搞一个。

最终效果:

实现的功能:上个月、当月、下个月和回到今天切换功能。

对应的html部分

   <div class="plan-zone">
            <div class="btn-group">
              <div class="left-btn">
                <el-button-group>
                  <el-button @click="prevMonth" type="primary"
                    >上一个月</el-button
                  >
                  <el-button type="primary" @click="goToCurrentMonth">{{
                    getCurDate()
                  }}</el-button>
                  <el-button @click="nextMonth" type="primary"
                    >下一个月</el-button
                  >
                </el-button-group>
                <el-button type="primary" @click="goToCurrentDay"
                  >回到今天</el-button
                >
              </div>
              <div class="right-btn">
                <button class="new">新安排</button>
                <button class="ing">进行中</button>
                <button class="finish">已完成</button>
              </div>
            </div>
            <!-- <el-calendar v-model="value"> </el-calendar> -->
            <table class="parent-table">
              <thead>
                <th>周一</th>
                <th>周二</th>
                <th>周三</th>
                <th>周四</th>
                <th>周五</th>
                <th>周六</th>
                <th>周日</th>
              </thead>
              <tbody>
                <tr v-for="(week, windex) in weeks" :key="windex">
                  <td
                    v-for="(day, dindex) in week"
                    :class="{ highlight: isToday(day.date) }"
                    :key="dindex"
                  >
                    <div
                      class="content"
                      :class="{
                        faded: !isCurrentMonth(day.date),
                      }"
                    >
                      <div class="top-day">{{ day.date.getDate() }}日</div>
                      <div class="middle-event"></div>
                      <div class="bottom-event"></div>
                    </div>
                  </td>
                </tr>
              </tbody>
            </table>
          </div>

对应scss部分

.faded {
  opacity: 0.3;
}
.highlight {
  background: rgba(255, 220, 40, 0.15);
}
.plan-zone {
  margin-top: 10px;
  .btn-group {
    display: flex;
    justify-content: space-between;
    .right-btn {
      button.new {
        background-color: #fff;
        border: 1px solid #fff;
        color: #409eef;
        position: relative;
        &::before {
          content: "";
          width: 8px;
          height: 8px;
          border-radius: 50%;
          position: absolute;
          top: 7px;
          left: -3px;
          background-color: #409eef;
        }
      }
      button.ing {
        background-color: #fff;
        border: 1px solid #fff;
        color: #ff974a;
        position: relative;
        &::before {
          content: "";
          width: 8px;
          height: 8px;
          border-radius: 50%;
          position: absolute;
          top: 7px;
          left: -3px;
          background-color: #ff974a;
        }
      }
      button.finish {
        background-color: #fff;
        border: 1px solid #fff;
        color: #3dd599;
        position: relative;
        &::before {
          content: "";
          width: 8px;
          height: 8px;
          border-radius: 50%;
          position: absolute;
          top: 7px;
          left: -3px;
          background-color: #3dd599;
        }
      }
    }
  }
}
.parent-table {
  border-collapse: collapse;
  table-layout: fixed;
  width: 100%;
  margin-top: 20px;
  th,
  td {
    width: 14.4%;
    border: 1px solid #ddd;
  }
  td {
    padding: 2px 3px;

    .content {
      position: relative;
      min-height: 80px;
    }
    vertical-align: top;
    .top-day {
      text-align: right;
      font-size: 13px;
    }
  }
}
.table-date {
  display: flex;
  > div {
    flex: 1;
  }
}

对应的JavaScript部分

export default {
  data() {
    return {
      current: new Date(),
      today: new Date(),
    };
  },
  computed: {
    weeks() {
      return this.getMonthData(
        this.current.getFullYear(),
        this.current.getMonth() + 1
      );
    },
  },
  methods: {
    getCurDate() {
      var date = new Date();
      var year = date.getFullYear();
      var month = date.getMonth() + 1; // getMonth() returns a zero-based value (0-11)
      if (month < 10) {
        month = "0" + month; // add a leading zero if the month is a single digit
      }
      return year + "-" + month;
    },
    isToday(date) {
      let today = new Date();
      return (
        date.getDate() === today.getDate() &&
        date.getMonth() === today.getMonth() &&
        date.getFullYear() === today.getFullYear()
      );
    },
    goToCurrentDay() {
      this.current = new Date(this.today);
    },
    isCurrentMonth(date) {
      return date.getMonth() === this.current.getMonth();
    },
    prevMonth() {
      this.current.setMonth(this.current.getMonth() - 1);
      this.current = new Date(this.current);
      // console.log(this.current.getFullYear(), 'dedede')
    },
    nextMonth() {
      this.current.setMonth(this.current.getMonth() + 1);
      this.current = new Date(this.current);
    },
    goToCurrentMonth() {
      this.current = new Date(this.today);
    },
    getMonthData(year, month) {
      let weeks = [];
      let firstDay = new Date(year, month - 1, 1); // 这个月的第一天
      let lastDayOfCurrentMonth = new Date(year, month, 0); // 这个月的最后一天
      let lastDayOfPrevMonth = new Date(year, month - 1, 0); // 上个月的最后一天

      //这里的0有一个特殊的意义,它可以返回上个月的最后一天。也就是说,如果你想知道某个月有多少天,你可以创建一个日期对象,年份和月份设置为你想知道的月份,日期设置为0,然后调用getDate()方法,返回的就是那个月的天数。
      // new Date(year, month - 1, 0) 最后一个参数,超过当月天数重新排序,比如1月31天,最后一个参数为33返回2
      let startDayOfWeek = firstDay.getDay() === 0 ? 7 : firstDay.getDay(); // 开始是周几
      let dayCount = 1; // 当前日期的变量,初始值为1
      // 上一个月的天数
      let prevMonthDayCount = lastDayOfPrevMonth.getDate() - startDayOfWeek + 2; // 这是为了在日历中填充上个月的日期。
      // console.log(lastDayOfPrevMonth.getDate(), startDayOfWeek, prevMonthDayCount)
      for (let i = 0; i < 6; i++) {
        let week = [];
        for (let j = 0; j < 7; j++) {
         // 日期为上个月的日期,然后将这个日期对象添加到`week`数组中,同时`prevMonthDayCount`加1。
          if (i === 0 && j < startDayOfWeek - 1) {

            week.push({ date: new Date(year, month - 2, prevMonthDayCount++) });
            // 日期为下个月的日期,然后将这个日期对象添加到`week`数组中,同时`dayCount`加1
          } else if (dayCount > lastDayOfCurrentMonth.getDate()) {
            week.push({
              date: new Date(
                year,
                month,
                dayCount++ - lastDayOfCurrentMonth.getDate()
              ),
            });
           // 日期为这个月的日期,然后将这个日期对象添加到`week`数组中,同时`dayCount`加1
          } else {
            week.push({ date: new Date(year, month - 1, dayCount++) });
          }
        }
        weeks.push(week);
      }
      return weeks;
    }

  },
};

关键是上面的getMonthData方法。理解这个方法就理解了这个组件。

以上就是基于vue手动实现一个日历组件的详细内容,更多关于vue日历组件的资料请关注脚本之家其它相关文章!

相关文章

  • Vue使用Cropper实现图片裁剪功能

    Vue使用Cropper实现图片裁剪功能

    图片裁剪功能无论是用户头像的裁剪,还是图片内容的精确调整,都成为了提升用户体验的关键一环,本文将详细介绍如何在Vue.js项目中集成并使用Cropper.js实现一个强大的图片裁剪组件,需要的可以参考下
    2024-11-11
  • Vue3造轮子之Typescript配置highlight过程

    Vue3造轮子之Typescript配置highlight过程

    这篇文章主要介绍了Vue3造轮子之Typescript配置highlight过程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-07-07
  • vue中的模态对话框组件实现过程

    vue中的模态对话框组件实现过程

    这篇文章主要介绍了vue中的模态对话框组件实现过程,通过template定义组件,并添加相应的对话框样式,需要的朋友可以参考下
    2018-05-05
  • 在vue中:style 的使用方式汇总

    在vue中:style 的使用方式汇总

    在Vue开发中使用:style绑定样式是常见需求,应注意:class与:style的配合使用,错误的使用可能导致样式不生效,正确的方法是使用数组绑定多个样式,这些技巧有助于提高开发效率和保持代码整洁,感兴趣的朋友跟随小编一起看看吧
    2024-09-09
  • Vue可自定义tab组件用法实例

    Vue可自定义tab组件用法实例

    在本篇文章里小编给大家分享了关于Vue可自定义tab组件用法实例以及相关知识点,需要的朋友们参考下。
    2019-10-10
  • Vue3实现自定义Input组件的示例详解

    Vue3实现自定义Input组件的示例详解

    这篇文章主要为大家详细介绍了如何使用Vue3自定义实现一个类似el-input的组件,可以v-model双向绑定,感兴趣的小伙伴可以跟随小编一起学习一下
    2024-03-03
  • Vue + Element-ui的下拉框el-select获取额外参数详解

    Vue + Element-ui的下拉框el-select获取额外参数详解

    这篇文章主要介绍了Vue + Element-ui的下拉框el-select获取额外参数详解,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-08-08
  • 解读为什么vue前端项目要使用Nodejs

    解读为什么vue前端项目要使用Nodejs

    这篇文章主要介绍了解读为什么vue前端项目要使用Nodejs问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2025-03-03
  • vue中formdata传值给后台时参数为空的问题

    vue中formdata传值给后台时参数为空的问题

    这篇文章主要介绍了vue中formdata传值给后台时参数为空的问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-06-06
  • vue.js入门教程之计算属性

    vue.js入门教程之计算属性

    Vue.js 的内联表达式非常方便,但它最合适的使用场景是简单的布尔操作或字符串拼接。如果涉及更复杂的逻辑,你应该使用计算属性。这篇文章我们将一起学习vue.js的计算属性。什么是计算属性,为什么要用这东西呢?通过下面这篇文章你将解决这些问题,下面来一起看看吧。
    2016-09-09

最新评论