当前位置:首页 > VUE

vue实现滑动日历

2026-01-19 05:32:03VUE

实现滑动日历的基本思路

使用Vue实现滑动日历需要结合触摸事件(touchstart、touchmove、touchend)或第三方库(如hammer.js)处理滑动逻辑,动态计算日期数据并渲染视图。核心是通过数据驱动更新日历面板。

vue实现滑动日历

基础代码结构

<template>
  <div class="calendar-container" 
       @touchstart="handleTouchStart"
       @touchmove="handleTouchMove"
       @touchend="handleTouchEnd">
    <div class="calendar-header">
      {{ currentYear }}年{{ currentMonth }}月
    </div>
    <div class="calendar-week">
      <span v-for="day in weekDays" :key="day">{{ day }}</span>
    </div>
    <div class="calendar-days">
      <span v-for="(day, index) in visibleDays" 
            :key="index"
            :class="{ 'current-month': day.isCurrentMonth, 'today': day.isToday }">
        {{ day.date }}
      </span>
    </div>
  </div>
</template>

数据处理逻辑

<script>
export default {
  data() {
    return {
      weekDays: ['日', '一', '二', '三', '四', '五', '六'],
      currentDate: new Date(),
      touchStartX: 0
    }
  },
  computed: {
    currentYear() {
      return this.currentDate.getFullYear()
    },
    currentMonth() {
      return this.currentDate.getMonth() + 1
    },
    visibleDays() {
      const year = this.currentDate.getFullYear()
      const month = this.currentDate.getMonth()
      const firstDay = new Date(year, month, 1)
      const lastDay = new Date(year, month + 1, 0)

      // 生成当月天数数组
      const days = []
      for (let i = 1; i <= lastDay.getDate(); i++) {
        days.push({
          date: i,
          isCurrentMonth: true,
          isToday: this.isToday(year, month, i)
        })
      }

      // 补全前面空缺
      const firstDayWeek = firstDay.getDay()
      const prevMonthLastDay = new Date(year, month, 0).getDate()
      for (let i = 0; i < firstDayWeek; i++) {
        days.unshift({
          date: prevMonthLastDay - i,
          isCurrentMonth: false,
          isToday: false
        })
      }

      // 补全后面空缺
      const totalCells = Math.ceil(days.length / 7) * 7
      while (days.length < totalCells) {
        days.push({
          date: days.length - lastDay.getDate() - firstDayWeek + 1,
          isCurrentMonth: false,
          isToday: false
        })
      }

      return days
    }
  },
  methods: {
    isToday(year, month, day) {
      const today = new Date()
      return (
        year === today.getFullYear() &&
        month === today.getMonth() &&
        day === today.getDate()
      )
    },
    handleTouchStart(e) {
      this.touchStartX = e.touches[0].clientX
    },
    handleTouchMove(e) {
      e.preventDefault()
    },
    handleTouchEnd(e) {
      const touchEndX = e.changedTouches[0].clientX
      const diffX = touchEndX - this.touchStartX

      if (Math.abs(diffX) > 50) {
        if (diffX > 0) {
          this.prevMonth()
        } else {
          this.nextMonth()
        }
      }
    },
    prevMonth() {
      this.currentDate = new Date(
        this.currentDate.getFullYear(),
        this.currentDate.getMonth() - 1,
        1
      )
    },
    nextMonth() {
      this.currentDate = new Date(
        this.currentDate.getFullYear(),
        this.currentDate.getMonth() + 1,
        1
      )
    }
  }
}
</script>

样式设计

<style scoped>
.calendar-container {
  width: 100%;
  user-select: none;
}

.calendar-header {
  text-align: center;
  padding: 10px;
  font-size: 18px;
}

.calendar-week {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  text-align: center;
  padding: 5px 0;
}

.calendar-days {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  text-align: center;
  gap: 5px;
}

.calendar-days span {
  padding: 10px;
  border-radius: 50%;
}

.current-month {
  color: #333;
}

.today {
  background-color: #409eff;
  color: white;
}
</style>

进阶优化方案

添加动画效果增强用户体验

vue实现滑动日历

// 在data中添加
slideDirection: ''

// 修改月份切换方法
prevMonth() {
  this.slideDirection = 'left'
  this.currentDate = new Date(
    this.currentDate.getFullYear(),
    this.currentDate.getMonth() - 1,
    1
  )
},
nextMonth() {
  this.slideDirection = 'right'
  this.currentDate = new Date(
    this.currentDate.getFullYear(),
    this.currentDate.getMonth() + 1,
    1
  )
}

// 添加CSS过渡
.calendar-days {
  transition: transform 0.3s ease;
}
.calendar-days.left {
  transform: translateX(100%);
}
.calendar-days.right {
  transform: translateX(-100%);
}

使用第三方库方案

对于更复杂的滑动效果,可以考虑使用swiper.js:

npm install swiper vue-awesome-swiper
<template>
  <swiper @slideChange="onSlideChange">
    <swiper-slide v-for="(month, index) in months" :key="index">
      <!-- 日历内容 -->
    </swiper-slide>
  </swiper>
</template>

<script>
import { Swiper, SwiperSlide } from 'vue-awesome-swiper'
import 'swiper/css/swiper.css'

export default {
  components: {
    Swiper,
    SwiperSlide
  },
  methods: {
    onSlideChange(swiper) {
      this.currentDate = new Date(
        this.currentDate.getFullYear(),
        this.currentDate.getMonth() + (swiper.activeIndex - this.currentSlideIndex),
        1
      )
      this.currentSlideIndex = swiper.activeIndex
    }
  }
}
</script>

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

相关文章

vue实现a4打印模板

vue实现a4打印模板

使用Vue实现A4打印模板 在Vue中实现A4打印模板需要结合CSS的打印样式和Vue的模板渲染能力。以下是具体实现方法: 设置A4纸张尺寸 在CSS中定义A4纸张的标准尺寸(210mm × 297…

vue实现过滤

vue实现过滤

Vue实现过滤的方法 在Vue中实现数据过滤可以通过多种方式完成,以下是几种常见的方法: 使用计算属性过滤 计算属性是Vue中处理数据过滤的理想选择,它们基于响应式依赖进行缓存,只有在相关依赖发生改…

vue 实现滚动

vue 实现滚动

实现滚动的基本方法 在Vue中实现滚动效果可以通过多种方式完成,包括使用原生JavaScript、CSS或第三方库。以下是一些常见的方法: 使用window.scrollTo方法实现页面滚动 可以通…

vue实现排序

vue实现排序

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

vue实现标注

vue实现标注

Vue 实现标注功能的方法 使用 Vue 实现标注功能可以通过多种方式实现,以下介绍几种常见的方法: 1. 使用 HTML5 Canvas 实现标注 Canvas 提供了强大的绘图能力,适合实现复…

vue实现卡片

vue实现卡片

Vue 实现卡片组件的方法 使用 Vue 实现卡片组件可以通过多种方式完成,以下是几种常见的实现方法: 使用原生 HTML 和 CSS 在 Vue 单文件组件中,可以通过模板和样式直接实现卡片效果…