当前位置:首页 > VUE

vue实现滑动日历

2026-01-19 05:32:03VUE

实现滑动日历的基本思路

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

基础代码结构

<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>

进阶优化方案

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

// 在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:

vue实现滑动日历

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 指令实现

vue 指令实现

Vue 指令实现 Vue 指令是 Vue.js 提供的特殊属性,用于在 DOM 元素上添加特殊行为。指令以 v- 前缀开头,例如 v-model、v-if、v-for 等。以下是实现自定义指令和常用内…

vue能实现

vue能实现

Vue.js 是一个流行的前端框架,能够实现多种功能。以下是 Vue 能够实现的主要功能和特性: 响应式数据绑定 Vue 的核心特性之一是响应式数据绑定。通过数据驱动视图,当数据发生变化时,视图会自…

实现vue框架

实现vue框架

Vue框架的基本实现 Vue是一个渐进式JavaScript框架,用于构建用户界面。以下是实现Vue框架的基本步骤: 安装Vue 通过CDN引入Vue是最简单的方式: <script src…

vue实现多选

vue实现多选

Vue 实现多选功能 在 Vue 中实现多选功能可以通过多种方式完成,以下是常见的几种方法: 使用 v-model 绑定数组 通过 v-model 绑定到一个数组,可以实现多选功能。适用于复选框组(…

vue实现首页

vue实现首页

Vue 实现首页的基本步骤 安装 Vue.js 和相关依赖,可以通过 Vue CLI 或 Vite 快速初始化项目。Vue CLI 适合传统项目,Vite 更适合现代前端开发。 npm instal…

vue实现回复

vue实现回复

Vue 实现回复功能 在 Vue 中实现回复功能通常涉及前端表单交互、数据绑定和后端通信。以下是实现回复功能的详细步骤: 数据绑定与表单设计 使用 Vue 的 v-model 绑定回复框的输入内容,…