当前位置:首页 > VUE

vue 实现日历

2026-01-12 23:56:22VUE

实现基础日历结构

使用 Vue 的模板语法构建日历的网格布局,通常以 7 列(一周)和 5-6 行(月份天数)的表格形式展示。通过 v-for 循环渲染日期单元格,动态绑定样式和事件。

vue 实现日历

<template>
  <div class="calendar">
    <div class="header">
      <button @click="prevMonth">上一月</button>
      <h3>{{ currentYear }}年{{ currentMonth + 1 }}月</h3>
      <button @click="nextMonth">下一月</button>
    </div>
    <div class="weekdays">
      <span v-for="day in weekdays" :key="day">{{ day }}</span>
    </div>
    <div class="days">
      <span 
        v-for="(day, index) in days" 
        :key="index"
        :class="{ 'other-month': !day.isCurrentMonth, 'today': day.isToday }"
        @click="selectDay(day)">
        {{ day.date }}
      </span>
    </div>
  </div>
</template>

处理日期逻辑

通过 JavaScript 的 Date 对象计算当前月份的天数、起始星期以及上个月/下个月的残留日期。核心逻辑包括:

vue 实现日历

  1. 获取月份第一天和最后一天的星期数。
  2. 生成包含当前月、上月残留和下月补全的日期数组。
<script>
export default {
  data() {
    return {
      currentDate: new Date(),
      weekdays: ['日', '一', '二', '三', '四', '五', '六']
    };
  },
  computed: {
    currentYear() {
      return this.currentDate.getFullYear();
    },
    currentMonth() {
      return this.currentDate.getMonth();
    },
    days() {
      const year = this.currentYear;
      const month = this.currentMonth;
      const firstDay = new Date(year, month, 1).getDay();
      const lastDate = new Date(year, month + 1, 0).getDate();
      const prevLastDate = new Date(year, month, 0).getDate();

      const days = [];
      // 上月残留日期
      for (let i = firstDay - 1; i >= 0; i--) {
        days.push({
          date: prevLastDate - i,
          isCurrentMonth: false
        });
      }
      // 当前月日期
      for (let i = 1; i <= lastDate; i++) {
        const today = new Date();
        days.push({
          date: i,
          isCurrentMonth: true,
          isToday: today.getDate() === i && 
                   today.getMonth() === month && 
                   today.getFullYear() === year
        });
      }
      // 下月补全日期
      const remaining = 42 - days.length;
      for (let i = 1; i <= remaining; i++) {
        days.push({
          date: i,
          isCurrentMonth: false
        });
      }
      return days;
    }
  },
  methods: {
    prevMonth() {
      this.currentDate = new Date(this.currentYear, this.currentMonth - 1, 1);
    },
    nextMonth() {
      this.currentDate = new Date(this.currentYear, this.currentMonth + 1, 1);
    },
    selectDay(day) {
      if (day.isCurrentMonth) {
        console.log(`选中日期: ${this.currentYear}-${this.currentMonth + 1}-${day.date}`);
      }
    }
  }
};
</script>

添加样式优化

通过 CSS 美化日历布局,区分当前月、非当前月及今日的样式。

<style scoped>
.calendar {
  width: 300px;
  border: 1px solid #eee;
  font-family: Arial, sans-serif;
}
.header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 10px;
  background: #f5f5f5;
}
.weekdays, .days {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  text-align: center;
}
.weekdays {
  background: #ddd;
  padding: 5px 0;
}
.days span {
  padding: 10px;
  cursor: pointer;
}
.other-month {
  color: #ccc;
}
.today {
  background: #4CAF50;
  color: white;
  border-radius: 50%;
}
</style>

扩展功能建议

  1. 事件标记:在日期单元格中显示自定义事件图标或文字。
  2. 范围选择:支持通过鼠标拖动选择日期范围。
  3. 国际化:根据地区动态切换星期显示顺序(如周一为首日)。
  4. 服务端集成:结合 API 拉取节假日或日程数据。

通过上述步骤,可实现一个基础的交互式 Vue 日历组件,后续可根据需求进一步扩展功能。

标签: 日历vue
分享给朋友:

相关文章

vue设计与实现 书

vue设计与实现 书

vue设计与实现 书 《Vue.js设计与实现》是一本深入探讨Vue.js框架内部原理和设计思想的书籍,适合希望深入理解Vue.js的开发者。以下是关于这本书的详细信息: 书籍内容 《Vue…

实现vue组件

实现vue组件

Vue 组件的基本实现 Vue 组件是 Vue.js 的核心特性之一,允许将 UI 拆分为独立、可复用的模块。以下是实现 Vue 组件的几种方式: 单文件组件 (SFC) 使用 .vue 文件格式,…

vue实现后退

vue实现后退

Vue 实现后退功能的方法 在 Vue 中实现后退功能通常可以通过以下几种方式完成,具体取决于应用场景和需求。 使用 window.history API 通过原生 JavaScript 的 win…

vue实现全景

vue实现全景

Vue 实现全景效果的方法 使用 Vue 实现全景效果通常需要结合第三方库或框架,以下是几种常见的方法: 使用 Three.js 和 Vue-Three.js Three.js 是一个强大的 3D…

vue实现删除

vue实现删除

Vue 实现删除功能的方法 在 Vue 中实现删除功能通常涉及以下几个步骤: 数据绑定与列表渲染 使用 v-for 指令渲染列表数据,并为每个项绑定唯一标识符(如 id)。例如: <ul&g…

vue实现单据

vue实现单据

Vue 实现单据功能的方法 使用 Vue 实现单据功能通常涉及表单设计、数据绑定、验证和提交等环节。以下是具体实现方案: 表单设计与数据绑定 使用 Vue 的 v-model 指令实现表单数据的双向…