当前位置:首页 > VUE

vue实现日历周滑动

2026-02-23 17:30:37VUE

Vue 实现日历周滑动功能

核心思路

日历周滑动通常需要结合触摸事件或手势库实现左右滑动切换周数。Vue中可通过计算属性动态生成每周日期数据,结合CSS过渡效果和触摸事件监听完成交互。

实现步骤

安装依赖(可选) 如需更流畅的手势支持,可安装hammerjsv-touch库:

npm install hammerjs

基础模板结构

<template>
  <div 
    class="calendar-week" 
    @touchstart="handleTouchStart"
    @touchmove="handleTouchMove"
    @touchend="handleTouchEnd"
  >
    <div class="week-container" :style="weekStyle">
      <div v-for="(day, index) in currentWeek" :key="index" class="day">
        <div class="weekday">{{ day.weekday }}</div>
        <div class="date">{{ day.date }}</div>
      </div>
    </div>
  </div>
</template>

JavaScript 逻辑

export default {
  data() {
    return {
      currentDate: new Date(),
      touchStartX: 0,
      touchEndX: 0,
      offsetX: 0,
      isSwiping: false
    }
  },
  computed: {
    currentWeek() {
      const weekdays = ['日', '一', '二', '三', '四', '五', '六'];
      const startOfWeek = this.getStartOfWeek(this.currentDate);

      return Array.from({ length: 7 }).map((_, i) => {
        const date = new Date(startOfWeek);
        date.setDate(date.getDate() + i);
        return {
          weekday: weekdays[date.getDay()],
          date: date.getDate(),
          fullDate: date
        };
      });
    },
    weekStyle() {
      return {
        transform: `translateX(${this.offsetX}px)`,
        transition: this.isSwiping ? 'none' : 'transform 0.3s ease'
      };
    }
  },
  methods: {
    getStartOfWeek(date) {
      const d = new Date(date);
      const day = d.getDay();
      const diff = d.getDate() - day + (day === 0 ? -6 : 1);
      return new Date(d.setDate(diff));
    },
    handleTouchStart(e) {
      this.touchStartX = e.touches[0].clientX;
      this.isSwiping = true;
    },
    handleTouchMove(e) {
      this.touchEndX = e.touches[0].clientX;
      this.offsetX = this.touchEndX - this.touchStartX;
    },
    handleTouchEnd() {
      this.isSwiping = false;
      const threshold = 50;

      if (this.offsetX > threshold) {
        this.prevWeek();
      } else if (this.offsetX < -threshold) {
        this.nextWeek();
      }

      this.offsetX = 0;
    },
    nextWeek() {
      const newDate = new Date(this.currentDate);
      newDate.setDate(newDate.getDate() + 7);
      this.currentDate = newDate;
    },
    prevWeek() {
      const newDate = new Date(this.currentDate);
      newDate.setDate(newDate.getDate() - 7);
      this.currentDate = newDate;
    }
  }
}

CSS 样式

.calendar-week {
  overflow: hidden;
  width: 100%;
  position: relative;
}

.week-container {
  display: flex;
  width: 100%;
}

.day {
  flex: 1;
  text-align: center;
  padding: 10px 0;
  min-width: calc(100% / 7);
}

.weekday {
  font-size: 12px;
  color: #666;
}

.date {
  font-size: 16px;
  margin-top: 4px;
}

进阶优化

添加周数指示器 可在顶部添加当前周数显示:

<div class="week-header">
  {{ currentDate | weekRange }}
</div>

添加过滤器

filters: {
  weekRange(date) {
    const start = this.getStartOfWeek(date);
    const end = new Date(start);
    end.setDate(end.getDate() + 6);
    return `${start.getMonth()+1}月${start.getDate()}日 - ${end.getMonth()+1}月${end.getDate()}日`;
  }
}

使用手势库(示例使用hammerjs)

vue实现日历周滑动

import Hammer from 'hammerjs';

mounted() {
  const mc = new Hammer(this.$el);
  mc.on('swipeleft', this.nextWeek);
  mc.on('swiperight', this.prevWeek);
}

注意事项

  • 触摸事件需考虑移动端兼容性
  • 过渡效果应避免在拖动过程中触发
  • 周数计算需处理跨月/跨年情况
  • 性能优化可考虑虚拟滚动处理大量日期

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

相关文章

vue实现一个标签选择

vue实现一个标签选择

Vue 标签选择组件实现 基础实现 使用 Vue 的 v-for 和 v-model 指令可以快速实现标签选择功能: <template> <div class="tag-se…

vue el 实现

vue el 实现

Vue 中使用 Element UI (el) 的实现方法 Element UI 是一个基于 Vue 的组件库,提供丰富的 UI 组件,常用于快速构建企业级中后台产品。以下介绍 Vue 项目中集成和使…

vue实现toast

vue实现toast

Vue 实现 Toast 的方法 使用第三方库(推荐) 对于快速实现 Toast 功能,推荐使用成熟的第三方库如 vue-toastification 或 vant 的 Toast 组件。 安装 v…

vue实现treeview

vue实现treeview

Vue 实现 TreeView 的方法 使用递归组件实现 TreeView 递归组件是 Vue 中实现 TreeView 的常见方式。通过组件调用自身,可以轻松处理嵌套的树形结构数据。 <te…

vue实现快手

vue实现快手

Vue 实现类似快手的功能 Vue.js 是一个渐进式 JavaScript 框架,适合构建复杂的单页应用。要实现类似快手的功能,可以结合 Vue 和相关技术栈进行开发。 核心功能模块 视频流展示…

vue最佳实现

vue最佳实现

Vue 最佳实践 组件设计 组件应遵循单一职责原则,每个组件只负责一个功能模块。命名采用 PascalCase(如 UserProfile.vue),模板中使用 kebab-case(如 <us…