当前位置:首页 > VUE

基于vue实现日历

2026-02-19 22:46:04VUE

实现基础日历框架

使用Vue的v-for指令循环生成日历格子,结合日期计算库(如date-fns)处理月份切换逻辑。初始化当前月份数据,计算该月天数及起始星期位置。

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

<script>
import { format, addMonths, startOfMonth, endOfMonth, eachDayOfInterval, getDay } from 'date-fns'

export default {
  data() {
    return {
      currentDate: new Date(),
      weekdays: ['日', '一', '二', '三', '四', '五', '六']
    }
  },
  computed: {
    currentMonth() {
      return format(this.currentDate, 'yyyy年MM月')
    },
    days() {
      const start = startOfMonth(this.currentDate)
      const end = endOfMonth(this.currentDate)
      const daysInMonth = eachDayOfInterval({ start, end })

      // 补齐前后空白日期
      const startDay = getDay(start)
      const prevMonthDays = Array(startDay).fill(null)
        .map((_, i) => ({
          date: '',
          isCurrentMonth: false
        }))

      const currentMonthDays = daysInMonth.map(date => ({
        date: format(date, 'd'),
        isCurrentMonth: true,
        fullDate: date
      }))

      return [...prevMonthDays, ...currentMonthDays]
    }
  },
  methods: {
    prevMonth() {
      this.currentDate = addMonths(this.currentDate, -1)
    },
    nextMonth() {
      this.currentDate = addMonths(this.currentDate, 1)
    }
  }
}
</script>

<style>
.calendar {
  width: 350px;
  font-family: Arial;
}
.header {
  display: flex;
  justify-content: space-between;
  align-items: center;
}
.weekdays, .days {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
}
.days div {
  height: 40px;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 1px solid #eee;
}
.other-month {
  background: #f9f9f9;
  color: #ccc;
}
</style>

添加日期选择功能

扩展基础日历,增加日期选中状态和点击事件处理。使用v-model实现双向数据绑定,支持外部控制选中日期。

<script>
export default {
  props: {
    value: Date
  },
  data() {
    return {
      selectedDate: this.value || null
    }
  },
  watch: {
    value(newVal) {
      this.selectedDate = newVal
    }
  },
  methods: {
    selectDate(day) {
      if (!day.isCurrentMonth) return
      this.selectedDate = day.fullDate
      this.$emit('input', day.fullDate)
    }
  }
}
</script>

<template>
  <!-- 在days的div中添加 -->
  <div 
    @click="selectDate(day)"
    :class="{ 
      'selected': selectedDate && day.fullDate && 
      format(selectedDate, 'yyyy-MM-dd') === format(day.fullDate, 'yyyy-MM-dd')
    }"
  >
    {{ day.date }}
  </div>
</template>

<style>
.selected {
  background: #42b983;
  color: white;
}
</style>

实现事件标记功能

添加事件数据支持,在特定日期显示标记点。通过计算属性筛选当前月份的事件,按日期分组渲染。

<script>
export default {
  props: {
    events: {
      type: Array,
      default: () => []
    }
  },
  computed: {
    eventMap() {
      return this.events.reduce((map, event) => {
        const dateKey = format(event.date, 'yyyy-MM-dd')
        map[dateKey] = event
        return map
      }, {})
    }
  }
}
</script>

<template>
  <div>
    {{ day.date }}
    <div v-if="day.fullDate" class="event-dot" 
         :style="{ backgroundColor: eventMap[format(day.fullDate, 'yyyy-MM-dd')]?.color }">
    </div>
  </div>
</template>

<style>
.event-dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  margin: 2px auto 0;
}
</style>

支持多语言和自定义样式

通过props接受自定义配置,使组件更具扩展性。添加i18n支持,允许覆盖默认的星期显示和日期格式。

<script>
export default {
  props: {
    locale: {
      type: Object,
      default: () => ({
        weekdays: ['日', '一', '二', '三', '四', '五', '六'],
        monthFormat: 'yyyy年MM月'
      })
    },
    theme: {
      type: Object,
      default: () => ({
        selectedColor: '#42b983',
        todayColor: '#ffeb3b'
      })
    }
  },
  computed: {
    currentMonth() {
      return format(this.currentDate, this.locale.monthFormat)
    },
    weekdays() {
      return this.locale.weekdays
    }
  }
}
</script>

完整组件集成示例

将上述功能整合为可直接使用的组件,暴露必要的事件和props接口。

<template>
  <div class="calendar" :style="{ '--selected-color': theme.selectedColor }">
    <!-- 组合所有模板部分 -->
  </div>
</template>

<script>
export default {
  name: 'VueCalendar',
  props: {
    value: Date,
    events: Array,
    locale: Object,
    theme: Object
  },
  // 组合所有脚本部分
}
</script>

<style scoped>
/* 组合所有样式部分 */
.selected {
  background: var(--selected-color);
}
</style>

使用时通过props传递配置和事件:

<vue-calendar 
  v-model="selectedDate"
  :events="calendarEvents"
  :locale="{ weekdays: ['Sun', 'Mon', ...], monthFormat: 'MMM yyyy' }"
  @date-click="handleDateClick"
/>

基于vue实现日历

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

相关文章

vue实现全局遮罩层

vue实现全局遮罩层

实现全局遮罩层的方法 在Vue中实现全局遮罩层可以通过多种方式完成,以下是几种常见的实现方法: 使用Vue组件创建遮罩层 创建一个遮罩层组件,通过全局注册或动态挂载的方式实现全局调用。以下是一个简…

js实现vue

js实现vue

Vue.js 的基本实现方法 在 JavaScript 中实现 Vue.js 的功能,可以通过直接引入 Vue 库或使用现代构建工具(如 Vite 或 Webpack)。以下是几种常见的实现方式:…

vue实现删除

vue实现删除

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

vue实现排序

vue实现排序

Vue 实现排序的方法 在 Vue 中实现排序可以通过多种方式完成,以下是一些常见的方法: 使用计算属性排序数组 计算属性非常适合对数据进行排序,因为它会在依赖的数据变化时自动更新。以下是一个示例…

vue实现fullpage

vue实现fullpage

Vue 实现 FullPage 效果 在 Vue 中实现全屏滚动(FullPage)效果可以通过多种方式完成,以下是几种常见的方法: 使用现有库 vue-fullpage.js 安装 vue-fu…

vue实现ppt

vue实现ppt

Vue 实现 PPT 的功能 Vue 可以结合第三方库或自定义组件实现类似 PPT 的演示效果。以下是几种常见的方法: 使用第三方库 reveal.js reveal.js 是一个流行的演示框架,支…