当前位置:首页 > 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>

进阶优化方案

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

// 在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
分享给朋友:

相关文章

vue中如何实现循环

vue中如何实现循环

在 Vue 中实现循环 Vue 提供了 v-for 指令用于实现循环渲染列表数据。v-for 可以遍历数组、对象或数字范围,生成动态的 DOM 元素。 遍历数组 使用 v-for 遍历数组时,语法为…

vue里实现增删改查

vue里实现增删改查

在Vue中实现增删改查 数据初始化 在Vue组件的data中定义初始数据和表单绑定的变量: data() { return { items: [ { id: 1, name…

vue实现菜单栏锚点

vue实现菜单栏锚点

实现锚点菜单的基本思路 在Vue中实现菜单栏锚点功能,主要涉及两个方面:创建可跳转的锚点位置,以及菜单项的点击滚动控制。通过监听滚动事件可以高亮当前可见区域的对应菜单项。 创建页面锚点位置 在需要…

vue实现app

vue实现app

Vue 实现 App 的常见方法 使用 Vue 开发移动端 App 主要有两种主流方案:混合开发(Hybrid)和原生渲染。以下是具体实现方式和工具链: 混合开发方案(WebView 嵌入) 通过…

简单实现vue

简单实现vue

Vue 的基本实现 创建一个简单的 Vue 应用需要引入 Vue 库,并编写基本的模板和数据绑定逻辑。 <!DOCTYPE html> <html lang="en"> &l…

vue页面实现

vue页面实现

Vue 页面实现方法 创建 Vue 组件 使用 Vue 单文件组件(SFC)方式创建页面,文件扩展名为 .vue。一个基本的 Vue 组件包含三个部分:模板(template)、脚本(script)和…