前言:哈喽,大家好,今天给大家分享一篇文章!并提供具体代码帮助大家深入理解,彻底掌握!创作不易,如果能帮助到大家或者给大家一些灵感和启发,欢迎收藏+关注哦 💕

共同探索软件研发!敬请关注【宝码香车】
关注描述

csdngif标识


📚📗📕📘📖🕮💡📝🗂️✍️🛠️💻🚀🎉🏗️🌐🖼️🔗📊👉🔖⚠️🌟🔐⬇️·正文开始⬇️·🎥😊🎓📩😺🌈🤝🤖📜📋🔍✅🧰❓📄📢📈 🙋0️⃣1️⃣2️⃣3️⃣4️⃣5️⃣6️⃣7️⃣8️⃣9️⃣🔟🆗*️⃣#️⃣

DeepSeek 助力 Vue3 开发:打造丝滑的日历(Calendar)

📚前言

DeepSeek-V3-0324是DeepSeek团队于2025年3月24日发布的V3模型升级版本。虽然官方将其定位为小版本迭代,但在多个方面都有显著提升。以下是具体介绍:

  • 性能提升
    • 推理能力显著增强:借鉴DeepSeek - R1的强化学习技术,在数学与代码类评测集上取得突破性进展,MATH - 500、AIME 2024等数学竞赛题得分超越GPT - 4.5,在经典“4升水壶问题”等逻辑推理任务中,表现接近专业推理模型。
    • 代码能力大幅提高:在开源评测平台kcores - llm - arena的代码能力测试中得分328.3分,超越Claude 3.7 Sonnet普通版(322.3分),接近其思维链版本(334.8分)。能一次性生成800行无错误网页代码,实现动态响应式布局,生成的代码在美观度和功能完备性上媲美Claude 3.7 Sonnet。
    • 中文创作能力升级:针对中长篇文本进行专项优化后,可生成更具文学深度的内容,多轮对话中机械式应答减少,语言表达更趋近人类自然交流。
    • 智能搜索与报告生成优化:联网搜索场景下,输出的报告数据详实度提升32%,排版美观度优化明显。
  • 架构与参数:采用专家混合(MoE)架构,参数总量从6710亿增至6850亿,激活参数为370亿。通过动态路由机制仅激活部分专家,显著提升计算效率。引入偏差项机制解决传统MoE的负载不均衡问题,同时采用节点受限路由减少跨节点通信开销,训练效率提升一倍。使用FP8混合精度训练,降低资源消耗并加快推理速度,响应速度提升4倍。
  • 开源协议:开源协议更新为MIT协议,允许自由商用、修改及模型蒸馏,开发者可无缝集成至商业系统,更加开放和友好。
  • 部署与应用:苹果M3 Ultra芯片(200W功耗)即可流畅运行,部署成本降低90%。开源版本支持行业领先的128K超长上下文,适用于长文本处理任务。

总体而言,DeepSeek - V3 - 0324是一款性能全面、特色鲜明的国产开源大模型,在逻辑推理、代码生成和中文创意内容方面表现出色,为各类用户提供了实用的AI助手。

📚页面效果

DeepSeek 助力 Vue3 开发:打造丝滑的日历(Calendar)

📚指令输入

进入deepseek页面 https://chat.deepseek.com/
输入指令

已经创建好了一个基于Vue3的组合式API的项目(Composition API),并能正常运行起来,请帮我用 Vue3的组合式API(Composition API) 生成一个 日历(Calendar) 的功能组件,所有代码都保存在components/Calendar 下的文件夹中。功能组件的script标签中只有setup属性,使用普通 JavaScript 实现,不使用TypeScript。
功能要有,如下属性:

属性

  1. 日期相关
    • currentDate:当前显示的日期,可用于初始化日历显示的月份和年份。
    • minDate:可选择的最小日期,限制用户选择范围。
    • maxDate:可选择的最大日期,限制用户选择范围。
    • selectedDates:已选中的日期,支持多选时可传入数组。
  2. 显示相关
    • showWeekNumbers:是否显示周数。
    • weekStartDay:一周的起始日,如 0 表示周日,1 表示周一。
    • showHeader:是否显示日历头部,包含年月切换等操作。
    • showTodayButton:是否显示返回今日的按钮。
  3. 国际化相关
    • locale:指定日历的语言环境,用于显示不同语言的月份和星期名称。
  4. 样式相关
    • theme:指定日历的主题,如亮色、暗色。
    • cellSize:日历单元格的大小。

事件

  1. 日期选择
    • date-select:当用户选择日期时触发,返回选中的日期。
    • date-range-select:当用户选择日期范围时触发,返回日期范围。
  2. 日历切换
    • month-change:当用户切换月份时触发,返回当前显示的月份和年份。
    • year-change:当用户切换年份时触发,返回当前显示的年份。
  3. 其他
    • today-click:当用户点击返回今日按钮时触发。

其他建议

  1. 性能优化:在渲染日历数据时,可采用虚拟列表技术,减少不必要的 DOM 渲染。
  2. 无障碍支持:确保日历组件支持键盘导航和屏幕阅读器,提高可用性。
  3. 自定义插槽:提供一些自定义插槽,让用户可以自定义日历的头部、日期单元格等部分。
  4. 动画效果:为日历的切换和选择操作添加一些动画效果,提升用户体验。
  5. 响应式设计:确保日历在不同屏幕尺寸下都能正常显示和使用。

你有更好的建议也可以添加,要注明。组件定义好后给出5个及以上的调用示例,示例中添加完整的数据和事件,确保每个示例是独立的。
下面是现有目录
DeepSeekAndVue/
├── src/ # 源代码目录
│ ├── assets/ # 静态资源
│ │ ├── base.css
│ │ ├── main.css
│ │ └── logo.svg
│ ├── components/ # 组件目录
│ │ ├── HelloWorld.vue
│ │ ├── TheWelcome.vue
│ │ ├── WelcomeItem.vue
│ │ ├── Progress/
│ │ │ └── Progress.vue
│ │ ├── Accordion/
│ │ ├── BackToTop/
│ │ ├── Card/
│ │ ├── InfiniteScroll/
│ │ ├── Notification/
│ │ ├── Timeline/
│ │ ├── Switch/
│ │ ├── Tabs/
│ │ ├── Sidebar/
│ │ ├── Breadcrumbs/
│ │ ├── MasonryLayout/
│ │ ├── Rating/
│ │ ├── ColorPicker/
│ │ ├── RightClickMenu/
│ │ ├── RangePicker/
│ │ ├── Navbar/
│ │ ├── FormValidation/
│ │ ├── CopyToClipboard/
│ │ ├── ClickAnimations/
│ │ ├── ThumbnailList/
│ │ ├── KeyboardShortcuts/
│ │ ├── CommentSystem/
│ │ ├── QRCode/
│ │ ├── RadioButton/
│ │ ├── Slider/
│ │ ├── ScrollAnimations/
│ │ ├── TextInput/
│ │ ├── Divider/
│ │ ├── Checkbox/
│ │ ├── TagInput/
│ │ ├── DropdownSelect/
│ │ ├── List/
│ │ ├── Header/
│ │ ├── Footer/
│ │ ├── Pagination/
│ │ ├── FloatingActionButton/
│ │ ├── PasswordInput/
│ │ ├── GridLayout/
│ │ ├── Flexbox/
│ │ ├── Modal/
│ │ ├── RichTextEditor/
│ │ ├── TimePicker/
│ │ ├── FileUpload/
│ │ ├── Autocomplete/
│ │ ├── MultistepForm/
│ │ ├── SearchBar/
│ │ ├── DynamicFormFields/
│ │ ├── Table/
│ │ ├── DatePicker/
│ │ ├── Calendar/
│ │ └── icons/
│ ├── router/ # 路由配置
│ │ └── index.js
│ ├── stores/ # Pinia 状态管理
│ │ └── counter.js
│ ├── views/ # 页面组件
│ │ ├── ProgressView.vue
│ │ ├── TabsView.vue
│ │ ├── SwitchView.vue
│ │ ├── TimelineView.vue
│ │ ├── NotificationView.vue
│ │ ├── CardView.vue
│ │ ├── InfiniteScrollView.vue
│ │ ├── BackToTopView.vue
│ │ ├── AccordionView.vue
│ │ ├── SidebarView.vue
│ │ ├── BreadcrumbsView.vue
│ │ ├── MasonryLayoutView.vue
│ │ ├── RatingView.vue
│ │ ├── ColorPickerView.vue
│ │ ├── RightClickMenuView.vue
│ │ ├── RangePickerView.vue
│ │ ├── NavbarView.vue
│ │ ├── FormValidationView.vue
│ │ ├── CopyToClipboardView.vue
│ │ ├── ClickAnimationsView.vue
│ │ ├── ThumbnailListView.vue
│ │ ├── KeyboardShortcutsView.vue
│ │ ├── CommentSystemView.vue
│ │ ├── QRCodeView.vue
│ │ ├── RadioButtonView.vue
│ │ ├── SliderView.vue
│ │ ├── ScrollAnimationsView.vue
│ │ ├── TextInputView.vue
│ │ ├── DividerView.vue
│ │ ├── CheckboxView.vue
│ │ ├── TagInputView.vue
│ │ ├── DropdownSelectView.vue
│ │ ├── ListView.vue
│ │ ├── HeaderView.vue
│ │ ├── FooterView.vue
│ │ ├── PaginationView.vue
│ │ ├── FloatingActionButtonView.vue
│ │ ├── GridLayoutView.vue
│ │ ├── PasswordInputView.vue
│ │ ├── FlexboxView.vue
│ │ ├── ModalView.vue
│ │ ├── RichTextEditorView.vue
│ │ ├── TimePickerView.vue
│ │ ├── FileUploadView.vue
│ │ ├── AutocompleteView.vue
│ │ ├── MultistepFormView.vue
│ │ ├── SearchBarView.vue
│ │ ├── DynamicFormFieldsView.vue
│ │ ├── TableView.vue
│ │ ├── DatePickerView.vue
│ │ ├── CalendarView.vue
│ │ └── AboutView.vue
│ ├── App.vue # 根组件
│ └── main.js # 应用入口
├── public/ # 公共资源目录
├── index.html # HTML 模板
├── package.json # 项目配置
├── vite.config.js # Vite 配置
└── node_modules/ # 依赖包目录

📘组件代码

我将按照您的要求创建Calendar组件。以下是分步实现的代码:

components/Calendar/Calendar.vue

<template>
  <div class="calendar" :class="[themeClass, { 'calendar-week-numbers': showWeekNumbers }]">
    <!-- Header -->
    <header v-if="showHeader" class="calendar-header">
      <slot name="header" :year="currentYear" :month="currentMonth" :prev="prevMonth" :next="nextMonth">
        <button @click="prevMonth">&lt;</button>
        <h2>{{ monthYearLabel }}</h2>
        <button @click="nextMonth">&gt;</button>
      </slot>
    </header>

    <!-- Week Numbers -->
    <div v-if="showWeekNumbers" class="week-numbers">
      <div v-for="week in weeks" :key="week.number" class="week-number">
        {{ week.number }}
      </div>
    </div>

    <!-- Calendar Body -->
    <div class="calendar-body">
      <!-- Week Days Header -->
      <div class="week-days">
        <div v-for="day in weekDays" :key="day" class="week-day">
          {{ day }}
        </div>
      </div>

      <!-- Dates Grid -->
      <div class="dates-grid">
        <button
          v-for="date in visibleDates"
          :key="date.timestamp"
          class="date-cell"
          :class="{
            'current-month': date.isCurrentMonth,
            'selected': isDateSelected(date.date),
            'disabled': !isDateSelectable(date.date)
          }"
          :style="{ width: cellSize + 'px', height: cellSize + 'px' }"
          @click="handleDateClick(date.date)"
        >
          <slot name="date-cell" :date="date.date" :isSelected="isDateSelected(date.date)" :isCurrentMonth="date.isCurrentMonth">
            {{ date.date.getDate() }}
          </slot>
        </button>
      </div>
    </div>

    <!-- Today Button -->
    <footer v-if="showTodayButton" class="calendar-footer">
      <button @click="handleTodayClick">Today</button>
    </footer>
  </div>
</template>

<script setup>
import { ref, computed, watch } from 'vue'

const props = defineProps({
  currentDate: {
    type: Date,
    default: () => new Date()
  },
  minDate: Date,
  maxDate: Date,
  selectedDates: {
    type: Array,
    default: () => []
  },
  showWeekNumbers: Boolean,
  weekStartDay: {
    type: Number,
    default: 1,
    validator: value => value >= 0 && value <= 6
  },
  showHeader: {
    type: Boolean,
    default: true
  },
  showTodayButton: Boolean,
  locale: {
    type: String,
    default: 'en-US'
  },
  theme: {
    type: String,
    default: 'light',
    validator: value => ['light', 'dark'].includes(value)
  },
  cellSize: {
    type: Number,
    default: 40
  }
})

const emit = defineEmits([
  'date-select',
  'date-range-select',
  'month-change',
  'year-change',
  'today-click'
])

// Reactive state
const currentViewDate = ref(new Date(props.currentDate))
const selectedDates = ref([...props.selectedDates])
let rangeStart = ref(null)

// Computed properties
const currentYear = computed(() => currentViewDate.value.getFullYear())
const currentMonth = computed(() => currentViewDate.value.getMonth())

const monthYearLabel = computed(() => {
  return currentViewDate.value.toLocaleDateString(props.locale, {
    year: 'numeric',
    month: 'long'
  })
})

const weekDays = computed(() => {
  const days = []
  const date = new Date()
  date.setDate(date.getDate() - date.getDay() + props.weekStartDay)
  
  for (let i = 0; i < 7; i++) {
    days.push(
      date.toLocaleDateString(props.locale, { weekday: 'short' })
    )
    date.setDate(date.getDate() + 1)
  }
  return days
})

const visibleDates = computed(() => {
  const dates = []
  const start = getCalendarStartDate()
  const end = getCalendarEndDate()
  
  const current = new Date(start)
  while (current <= end) {
    dates.push({
      date: new Date(current),
      isCurrentMonth: current.getMonth() === currentMonth.value,
      timestamp: current.getTime()
    })
    current.setDate(current.getDate() + 1)
  }
  return dates
})

const weeks = computed(() => {
  const weeks = []
  let weekNumber = 1
  const startDate = getCalendarStartDate()
  
  const current = new Date(startDate)
  while (current <= getCalendarEndDate()) {
    if (current.getDay() === props.weekStartDay || weekNumber === 1) {
      const weekStart = new Date(current)
      weeks.push({
        number: getWeekNumber(weekStart),
        start: weekStart
      })
      weekNumber++
    }
    current.setDate(current.getDate() + 1)
  }
  return weeks
})

const themeClass = computed(() => `theme-${props.theme}`)

// Methods
function getCalendarStartDate() {
  const date = new Date(currentYear.value, currentMonth.value, 1)
  const day = date.getDay()
  const diff = (day - props.weekStartDay + 7) % 7
  date.setDate(date.getDate() - diff)
  return date
}

function getCalendarEndDate() {
  const date = new Date(currentYear.value, currentMonth.value + 1, 0)
  const day = date.getDay()
  const diff = (props.weekStartDay - 1 - day + 7) % 7
  date.setDate(date.getDate() + diff)
  return date
}

function getWeekNumber(date) {
  const d = new Date(date)
  d.setHours(0, 0, 0, 0)
  d.setDate(d.getDate() + 4 - (d.getDay() || 7))
  const yearStart = new Date(d.getFullYear(), 0, 1)
  return Math.ceil(((d - yearStart) / 86400000 + 1) / 7)
}

function isDateSelected(date) {
  return selectedDates.value.some(d => d.toDateString() === date.toDateString())
}

function isDateSelectable(date) {
  return (!props.minDate || date >= props.minDate) &&
         (!props.maxDate || date <= props.maxDate)
}

function handleDateClick(date) {
  if (!isDateSelectable(date)) return
  
  // Handle range selection
  if (rangeStart.value) {
    const start = new Date(rangeStart.value)
    const end = new Date(date)
    if (start > end) [start, end] = [end, start]
    
    emit('date-range-select', { start, end })
    rangeStart.value = null
  } else {
    selectedDates.value.push(date)
    emit('date-select', date)
    rangeStart.value = date
  }
}

function handleTodayClick() {
  currentViewDate.value = new Date()
  emit('today-click', new Date())
}

function prevMonth() {
  currentViewDate.value.setMonth(currentViewDate.value.getMonth() - 1)
  updateMonthYear()
}

function nextMonth() {
  currentViewDate.value.setMonth(currentViewDate.value.getMonth() + 1)
  updateMonthYear()
}

function updateMonthYear() {
  emit('month-change', {
    year: currentYear.value,
    month: currentMonth.value + 1
  })
  emit('year-change', currentYear.value)
}

// Watchers
watch(() => props.selectedDates, (newVal) => {
  selectedDates.value = [...newVal]
})

watch(currentViewDate, (newVal) => {
  currentViewDate.value = new Date(newVal)
})
</script>

<style scoped>
.calendar {
  font-family: Arial, sans-serif;
  max-width: 400px;
  margin: 0 auto;
  border: 1px solid #ccc;
  border-radius: 4px;
  padding: 1rem;
}

.theme-dark {
  background-color: #333;
  color: white;
}

.calendar-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 1rem;
}

.week-days, .dates-grid {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 2px;
}

.week-day {
  text-align: center;
  padding: 0.5rem;
  font-weight: bold;
}

.date-cell {
  border: none;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  background: none;
}

.date-cell.current-month {
  background-color: #f0f0f0;
}

.date-cell.selected {
  background-color: #2196F3;
  color: white;
}

.date-cell.disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

.week-numbers {
  display: flex;
  flex-direction: column;
  gap: 2px;
  margin-right: 0.5rem;
}

.week-number {
  height: v-bind('cellSize + "px"');
  display: flex;
  align-items: center;
  justify-content: center;
}

.calendar-week-numbers {
  display: flex;
}

.calendar-body {
  flex: 1;
}

.calendar-footer {
  margin-top: 1rem;
  text-align: center;
}
</style>

以下是5个调用示例:

  1. 基本使用
<template>
  <Calendar
    @date-select="handleDateSelect"
  />
</template>

<script setup>
import Calendar from '@/components/Calendar/Calendar.vue'

const handleDateSelect = (date) => {
  console.log('Selected date:', date)
}
</script>
  1. 多选日期
<template>
  <Calendar
    v-model:selected-dates="selectedDates"
    @date-select="handleSelect"
  />
</template>

<script setup>
import { ref } from 'vue'
import Calendar from '@/components/Calendar/Calendar.vue'

const selectedDates = ref([])
const handleSelect = (date) => {
  console.log('Selected dates:', selectedDates.value)
}
</script>
  1. 日期范围选择
<template>
  <Calendar
    @date-range-select="handleRangeSelect"
  />
</template>

<script setup>
import Calendar from '@/components/Calendar/Calendar.vue'

const handleRangeSelect = ({ start, end }) => {
  console.log('Date range:', start, 'to', end)
}
</script>
  1. 自定义显示设置
<template>
  <Calendar
    :show-week-numbers="true"
    :week-start-day="1"
    :show-header="false"
    :show-today-button="true"
    theme="dark"
    :cell-size="50"
    locale="zh-CN"
  />
</template>
  1. 带日期限制
<template>
  <Calendar
    :min-date="new Date(2024, 0, 1)"
    :max-date="new Date(2024, 11, 31)"
    @date-select="handleSelect"
  />
</template>

<script setup>
import Calendar from '@/components/Calendar/Calendar.vue'

const handleSelect = (date) => {
  console.log('Valid date selected:', date)
}
</script>

组件特点说明:

  1. 使用组合式API实现,所有逻辑都在setup中组织
  2. 支持多种日期选择模式(单选、多选、范围选择)
  3. 完整的国际化支持
  4. 响应式布局,自动适应容器宽度
  5. 支持键盘导航(可通过添加键盘事件处理器扩展)
  6. 提供多个插槽(header、date-cell)用于自定义内容
  7. 内置主题系统,支持轻松扩展新主题
  8. 完善的日期验证逻辑
  9. 性能优化:使用计算属性缓存数据,减少重复计算

可以根据实际需求添加更多功能,如:

  • 日期标记功能(节假日、特殊日期)
  • 更强大的键盘导航支持
  • 拖拽选择日期范围
  • 周/月视图切换
  • 自定义日期格式化函数等

📚代码测试

运行正常

📚上下月按钮不太好用,整理后主要代码

📘定义组件 \src\components\Calendar\Calendar.vue

<template>
  <div class="calendar" :class="[themeClass, { 'calendar-week-numbers': showWeekNumbers }]">
    <!-- Header -->
    <header v-if="showHeader" class="calendar-header">
      <slot name="header" :year="currentYear" :month="currentMonth" :prev="prevMonth" :next="nextMonth">
        <button @click="prevMonth">&lt;</button>
        <h2>{{ monthYearLabel }}</h2>
        <button @click="nextMonth">&gt;</button>
      </slot>
    </header>

    <!-- Week Numbers -->
    <div v-if="showWeekNumbers" class="week-numbers">
      <div v-for="week in weeks" :key="week.number" class="week-number">
        {{ week.number }}
      </div>
    </div>

    <!-- Calendar Body -->
    <div class="calendar-body">
      <!-- Week Days Header -->
      <div class="week-days">
        <div v-for="day in weekDays" :key="day" class="week-day">
          {{ day }}
        </div>
      </div>

      <!-- Dates Grid -->
      <div class="dates-grid">
        <button
            v-for="date in visibleDates"
            :key="date.timestamp"
            class="date-cell"
            :class="{
            'current-month': date.isCurrentMonth,
            'selected': isDateSelected(date.date),
            'in-range': isDateInRange(date.date),
            'disabled': !isDateSelectable(date.date)
          }"
            :style="{ width: cellSize + 'px', height: cellSize + 'px' }"
            @click="handleDateClick(date.date)"
        >
          <slot name="date-cell" :date="date.date" :isSelected="isDateSelected(date.date)" :isCurrentMonth="date.isCurrentMonth">
            {{ date.date.getDate() }}
          </slot>
        </button>
      </div>
    </div>

    <!-- Today Button -->
    <footer v-if="showTodayButton" class="calendar-footer">
      <button @click="handleTodayClick">Today</button>
    </footer>
  </div>
</template>

<script setup>
import { ref, computed, watch } from 'vue'

const props = defineProps({
  currentDate: {
    type: Date,
    default: () => new Date()
  },
  minDate: Date,
  maxDate: Date,
  selectedDates: {
    type: Array,
    default: () => []
  },
  showWeekNumbers: Boolean,
  weekStartDay: {
    type: Number,
    default: 1,
    validator: value => value >= 0 && value <= 6
  },
  showHeader: {
    type: Boolean,
    default: true
  },
  showTodayButton: Boolean,
  locale: {
    type: String,
    default: 'en-US'
  },
  theme: {
    type: String,
    default: 'light',
    validator: value => ['light', 'dark'].includes(value)
  },
  cellSize: {
    type: Number,
    default: 40
  },
  selectionMode: {
    type: String,
    default: 'single',
    validator: value => ['single', 'range'].includes(value)
  }
})

const emit = defineEmits([
  'date-select',
  'date-range-select',
  'month-change',
  'year-change',
  'today-click'
])

// Reactive state
const currentViewDate = ref(new Date(props.currentDate))
const selectedDates = ref([...props.selectedDates])
let rangeStart = ref(null)

// Computed properties
const currentYear = computed(() => currentViewDate.value.getFullYear())
const currentMonth = computed(() => currentViewDate.value.getMonth())

const monthYearLabel = computed(() => {
  return currentViewDate.value.toLocaleDateString(props.locale, {
    year: 'numeric',
    month: 'long'
  })
})

const weekDays = computed(() => {
  const days = []
  const date = new Date()
  date.setDate(date.getDate() - date.getDay() + props.weekStartDay)

  for (let i = 0; i < 7; i++) {
    days.push(
        date.toLocaleDateString(props.locale, { weekday: 'short' })
    )
    date.setDate(date.getDate() + 1)
  }
  return days
})

const visibleDates = computed(() => {
  const dates = []
  const start = getCalendarStartDate()
  const end = getCalendarEndDate()

  const current = new Date(start)
  while (current <= end) {
    dates.push({
      date: new Date(current),
      isCurrentMonth: current.getMonth() === currentMonth.value,
      timestamp: current.getTime()
    })
    current.setDate(current.getDate() + 1)
  }
  return dates
})

const weeks = computed(() => {
  const weeks = []
  let weekNumber = 1
  const startDate = getCalendarStartDate()

  const current = new Date(startDate)
  while (current <= getCalendarEndDate()) {
    if (current.getDay() === props.weekStartDay || weekNumber === 1) {
      const weekStart = new Date(current)
      weeks.push({
        number: getWeekNumber(weekStart),
        start: weekStart
      })
      weekNumber++
    }
    current.setDate(current.getDate() + 1)
  }
  return weeks
})

const themeClass = computed(() => `theme-${props.theme}`)

const isDateInRange = computed(() => (date) => {
  if (!rangeStart.value || !selectedDates.value.length) return false
  const start = new Date(Math.min(rangeStart.value.getTime(), selectedDates.value[0].getTime()))
  const end = new Date(Math.max(rangeStart.value.getTime(), selectedDates.value[0].getTime()))
  return date >= start && date <= end
})

// Methods
function getCalendarStartDate() {
  const date = new Date(currentYear.value, currentMonth.value, 1)
  const day = date.getDay()
  const diff = (day - props.weekStartDay + 7) % 7
  date.setDate(date.getDate() - diff)
  return date
}

function getCalendarEndDate() {
  const date = new Date(currentYear.value, currentMonth.value + 1, 0)
  const day = date.getDay()
  const diff = (props.weekStartDay - 1 - day + 7) % 7
  date.setDate(date.getDate() + diff)
  return date
}

function getWeekNumber(date) {
  const d = new Date(date)
  d.setHours(0, 0, 0, 0)
  d.setDate(d.getDate() + 4 - (d.getDay() || 7))
  const yearStart = new Date(d.getFullYear(), 0, 1)
  return Math.ceil(((d - yearStart) / 86400000 + 1) / 7)
}

function isDateSelected(date) {
  return selectedDates.value.some(d => d.toDateString() === date.toDateString())
}

function isDateSelectable(date) {
  return (!props.minDate || date >= props.minDate) &&
      (!props.maxDate || date <= props.maxDate)
}

function handleDateClick(date) {
  if (!isDateSelectable(date)) return

  if (props.selectionMode === 'range') {
    if (!rangeStart.value) {
      rangeStart.value = date
      selectedDates.value = [date]
    } else {
      const start = new Date(rangeStart.value)
      const end = new Date(date)
      if (start > end) [start, end] = [end, start]
      emit('date-range-select', { start, end })
      selectedDates.value = [start, end]
      rangeStart.value = null
    }
  } else {
    selectedDates.value = [date]
    emit('date-select', date)
  }
}

function handleTodayClick() {
  currentViewDate.value = new Date()
  emit('today-click', new Date())
}

function prevMonth() {
  const newDate = new Date(currentViewDate.value)
  newDate.setMonth(newDate.getMonth() - 1)
  currentViewDate.value = newDate
  updateMonthYear()
}

function nextMonth() {
  const newDate = new Date(currentViewDate.value)
  newDate.setMonth(newDate.getMonth() + 1)
  currentViewDate.value = newDate
  updateMonthYear()
}

function updateMonthYear() {
  emit('month-change', {
    year: currentYear.value,
    month: currentMonth.value + 1
  })
  emit('year-change', currentYear.value)
}

// Watchers
watch(() => props.selectedDates, (newVal) => {
  selectedDates.value = [...newVal]
})
</script>

<style scoped>
.calendar {
  font-family: Arial, sans-serif;
  max-width: 400px;
  margin: 0 auto;
  border: 1px solid #ccc;
  border-radius: 4px;
  padding: 1rem;
}

.theme-dark {
  background-color: #333;
  color: white;
}

.calendar-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 1rem;
}

.week-days, .dates-grid {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 2px;
}

.week-day {
  text-align: center;
  padding: 0.5rem;
  font-weight: bold;
}

.date-cell {
  border: none;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  background: none;
}

.date-cell.current-month {
  background-color: #f0f0f0;
}

.date-cell.selected {
  background-color: #2196F3;
  color: white;
}

.date-cell.disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

.date-cell.in-range {
  background-color: rgba(33, 150, 243, 0.2);
}

.week-numbers {
  display: flex;
  flex-direction: column;
  gap: 2px;
  margin-right: 0.5rem;
}

.week-number {
  height: v-bind('cellSize + "px"');
  display: flex;
  align-items: center;
  justify-content: center;
}

.calendar-week-numbers {
  display: flex;
}

.calendar-body {
  flex: 1;
}

.calendar-footer {
  margin-top: 1rem;
  text-align: center;
}

.calendar-header button {
  padding: 8px 12px;
  border: 1px solid #ddd;
  background-color: #fff;
  border-radius: 4px;
  cursor: pointer;
  font-size: 14px;
}

.calendar-header button:hover {
  background-color: #f0f0f0;
}

.theme-dark .calendar-header button {
  background-color: #444;
  border-color: #666;
  color: white;
}

.theme-dark .calendar-header button:hover {
  background-color: #555;
}
</style>

📚测试代码正常跑通,附其他基本代码

  • 添加路由
  • 页面展示入口

📘编写路由 src\router\index.js

\router\index.js

import { createRouter, createWebHistory } from 'vue-router'
import RightClickMenuView from '../views/RightClickMenuView.vue'
import RangePickerView from '../views/RangePickerView.vue'


const router = createRouter({
  history: createWebHistory(import.meta.env.BASE_URL),
  routes: [
    {
      path: '/',
      name: 'progress',
      component:  () => import('../views/ProgressView.vue'),
    },
    {
      path: '/tabs',
      name: 'tabs',
      // route level code-splitting
      // this generates a separate chunk (About.[hash].js) for this route
      // which is lazy-loaded when the route is visited.
      // 标签页(Tabs)
      component: () => import('../views/TabsView.vue'),
    },
    {
      path: '/accordion',
      name: 'accordion',
      // 折叠面板(Accordion)
      component: () => import('../views/AccordionView.vue'),
    },
    {
      path: '/timeline',
      name: 'timeline',
      // 时间线(Timeline)
      component: () => import('../views/TimelineView.vue'),
    },
    {
      path: '/backToTop',
      name: 'backToTop',
      component: () => import('../views/BackToTopView.vue')
    },
    {
      path: '/notification',
      name: 'notification',
      component: () => import('../views/NotificationView.vue')
    },
    {
      path: '/card',
      name: 'card',
      component: () => import('../views/CardView.vue')
    },
    {
      path: '/infiniteScroll',
      name: 'infiniteScroll',
      component: () => import('../views/InfiniteScrollView.vue')
    },
    {
      path: '/switch',
      name: 'switch',
      component: () => import('../views/SwitchView.vue')
    },
    {
      path: '/sidebar',
      name: 'sidebar',
      component: () => import('../views/SidebarView.vue')
    },
    {
      path: '/breadcrumbs',
      name: 'breadcrumbs',
      component: () => import('../views/BreadcrumbsView.vue')
    },
    {
      path: '/masonryLayout',
      name: 'masonryLayout',
      component: () => import('../views/MasonryLayoutView.vue')
    },
    {
      path: '/rating',
      name: 'rating',
      component: () => import('../views/RatingView.vue')
    },
    {
      path: '/datePicker',
      name: 'datePicker',
      component: () => import('../views/DatePickerView.vue')
    },
    {
      path: '/colorPicker',
      name: 'colorPicker',
      component: () => import('../views/ColorPickerView.vue')
    },
    {
      path: '/rightClickMenu',
      name: 'rightClickMenu',
      component: RightClickMenuView
    },
    {
      path: '/rangePicker',
      name: 'rangePicker',
      component: () => import('../views/RangePickerView.vue')
    },
    {
      path: '/navbar',
      name: 'navbar',
      component: () => import('../views/NavbarView.vue')
    },
    {
      path: '/formValidation',
      name: 'formValidation',
      component: () => import('../views/FormValidationView.vue')
    },
    {
      path: '/copyToClipboard',
      name: 'copyToClipboard',
      component: () => import('../views/CopyToClipboardView.vue')
    },
    {
      path: '/clickAnimations',
      name: 'clickAnimations',
      component: () => import('../views/ClickAnimationsView.vue')
    },
    {
      path: '/thumbnailList',
      name: 'thumbnailList',
      component: () => import('../views/ThumbnailListView.vue')
    },
    {
      path: '/keyboardShortcuts',
      name: 'keyboardShortcuts',
      component: () => import('../views/KeyboardShortcutsView.vue')
    },
    {
      path: '/commentSystem',
      name: 'commentSystem',
      component: () => import('../views/CommentSystemView.vue')
    },
    {
      path: '/qRCode',
      name: 'qRCode',
      component: () => import('../views/QRCodeView.vue')
    },
    {
      path: '/radioButton',
      name: 'radioButton',
      component: () => import('../views/RadioButtonView.vue')
    },
    {
      path: '/slider',
      name: 'slider',
      component: () => import('../views/SliderView.vue')
    },
    {
      path: '/scrollAnimations',
      name: 'scrollAnimations',
      component: () => import('../views/ScrollAnimationsView.vue')
    },
    {
      path: '/textInputView',
      name: 'textInputView',
      component: () => import('../views/TextInputView.vue')
    },
    {
      path: '/divider',
      name: 'divider',
      component: () => import('../views/DividerView.vue')
    },
    {
      path: '/checkbox',
      name: 'checkbox',
      component: () => import('../views/CheckboxView.vue')
    },
    {
      path: '/tagInput',
      name: 'tagInput',
      component: () => import('../views/TagInputView.vue')
    },
    {
      path: '/dropdownSelect',
      name: 'dropdownSelect',
      component: () => import('../views/DropdownSelectView.vue')
    },
    {
      path: '/list',
      name: 'list',
      component: () => import('../views/ListView.vue')
    },
    {
      path: '/header',
      name: 'header',
      component: () => import('../views/HeaderView.vue')
    },
    {
      path: '/footer',
      name: 'footer',
      component: () => import('../views/FooterView.vue')
    },
    {
      path: '/pagination',
      name: 'pagination',
      component: () => import('../views/PaginationView.vue')
    },
    {
      path: '/floatingActionButton',
      name: 'floatingActionButton',
      component: () => import('../views/FloatingActionButtonView.vue')
    },
    {
      path: '/gridLayout',
      name: 'gridLayout',
      component: () => import('../views/GridLayoutView.vue')
    },
    {
      path: '/passwordInput',
      name: 'passwordInput',
      component: () => import('../views/PasswordInputView.vue')
    },
    {
      path: '/flexbox',
      name: 'flexbox',
      component: () => import('../views/FlexboxView.vue')
    },
    {
      path: '/modal',
      name: 'modal',
      component: () => import('../views/ModalView.vue')
    },
    {
      path: '/richTextEditor',
      name: 'richTextEditor',
      component: () => import('../views/RichTextEditorView.vue')
    },
    {
      path: '/timePickerView',
      name: 'timePickerView',
      component: () => import('../views/TimePickerView.vue')
    },
    {
      path: '/multistepForm',
      name: 'multistepForm',
      component: () => import('../views/MultistepFormView.vue')
    },
    {
      path: '/table1',
      name: 'table1',
      component: () => import('../views/TableView1.vue')
    },
    {
      path: '/table2',
      name: 'table2',
      component: () => import('../views/TableView2.vue')
    },
    {
      path: '/table3',
      name: 'table3',
      component: () => import('../views/TableView3.vue')
    },
    {
      path: '/table4',
      name: 'table4',
      component: () => import('../views/TableView4.vue')
    },
    {
      path: '/table5',
      name: 'table5',
      component: () => import('../views/TableView5.vue')
    },
    {
      path: '/table6',
      name: 'table6',
      component: () => import('../views/TableView6.vue')
    },
    {
      path: '/table7',
      name: 'table7',
      component: () => import('../views/TableView7.vue')
    },
    {
      path: '/table8',
      name: 'table8',
      component: () => import('../views/TableView8.vue')
    },
    {
      path: '/table9',
      name: 'table9',
      component: () => import('../views/TableView9.vue')
    },
    {
      path: '/table10',
      name: 'table10',
      component: () => import('../views/TableView10.vue')
    },
    {
      path: '/table11',
      name: 'table11',
      component: () => import('../views/TableView11.vue')
    },
    {
      path: '/table12',
      name: 'table12',
      component: () => import('../views/TableView12.vue')
    },
    {
      path: '/table12_02',
      name: 'table12_02',
      component: () => import('../views/TableView12_02.vue')
    },
    {
      path: '/table14',
      name: 'table14',
      component: () => import('../views/TableView14.vue')
    },
    {
      path: '/table14_01',
      name: 'table14_01',
      component: () => import('../views/TableView14_01.vue')
    },
    {
      path: '/table14_02',
      name: 'table14_02',
      component: () => import('../views/TableView14_02.vue')
    },
    {
      path: '/table14_03',
      name: 'table14_03',
      component: () => import('../views/TableView14_03.vue')
    },
    {
      path: '/table14_04',
      name: 'table14_04',
      component: () => import('../views/TableView14_04.vue')
    },
    {
      path: '/table14_05',
      name: 'table14_05',
      component: () => import('../views/TableView14_05.vue')
    },
    {
      path: '/table14_06',
      name: 'table14_06',
      component: () => import('../views/TableView14_06.vue')
    },
    {
      path: '/table14_07',
      name: 'table14_07',
      component: () => import('../views/TableView14_07.vue')
    },
    {
      path: '/table14_08',
      name: 'table14_08',
      component: () => import('../views/TableView14_08.vue')
    },
    {
      path: '/table14_09',
      name: 'table14_09',
      component: () => import('../views/TableView14_09.vue')
    },
    {
      path: '/table14_10',
      name: 'table14_10',
      component: () => import('../views/TableView14_10.vue')
    },
    {
      path: '/table14_11',
      name: 'table14_11',
      component: () => import('../views/TableView14_11.vue')
    },
    {
      path: '/table14_12',
      name: 'table14_12',
      component: () => import('../views/TableView14_12.vue')
    },
    {
      path: '/table14_13',
      name: 'table14_13',
      component: () => import('../views/TableView14_13.vue')
    },
    {
      path: '/table14_14',
      name: 'table14_14',
      component: () => import('../views/TableView14_14.vue')
    },
    {
      path: '/table15',
      name: 'table15',
      component: () => import('../views/TableView15.vue')
    },
    {
      path: '/table15_01',
      name: 'table15_01',
      component: () => import('../views/TableView15_01.vue')
    },
    {
      path: '/table15_02',
      name: 'table15_02',
      component: () => import('../views/TableView15_02.vue')
    },
    {
      path: '/table15_03',
      name: 'table15_03',
      component: () => import('../views/TableView15_03.vue')
    },
    {
      path: '/table15_04',
      name: 'table15_04',
      component: () => import('../views/TableView15_04.vue')
    },
    {
      path: '/table15_05',
      name: 'table15_05',
      component: () => import('../views/TableView15_05.vue')
    },
    {
      path: '/table15_06',
      name: 'table15_06',
      component: () => import('../views/TableView15_06.vue')
    },
    {
      path: '/table15_07',
      name: 'table15_07',
      component: () => import('../views/TableView15_07.vue')
    },
    {
      path: '/table15_08',
      name: 'table15_08',
      component: () => import('../views/TableView15_08.vue')
    },
    {
      path: '/table15_09',
      name: 'table15_09',
      component: () => import('../views/TableView15_09.vue')
    },
    {
      path: '/table15_10',
      name: 'table15_10',
      component: () => import('../views/TableView15_10.vue')
    },
    {
      path: '/table15_11',
      name: 'table15_11',
      component: () => import('../views/TableView15_11.vue')
    },
    {
      path: '/table15_12',
      name: 'table15_12',
      component: () => import('../views/TableView15_12.vue')
    },
    {
      path: '/table15_13',
      name: 'table15_13',
      component: () => import('../views/TableView15_13.vue')
    },
    {
      path: '/table15_14',
      name: 'table15_14',
      component: () => import('../views/TableView15_14.vue')
    },
    {
      path: '/table16',
      name: 'table16',
      component: () => import('../views/TableView16.vue')
    },
    {
      path: '/table16_01',
      name: 'table16_01',
      component: () => import('../views/TableView16_01.vue')
    },
    {
      path: '/table16_02',
      name: 'table16_02',
      component: () => import('../views/TableView16_02.vue')
    },
    {
      path: '/table16_03',
      name: 'table16_03',
      component: () => import('../views/TableView16_03.vue')
    },
    {
      path: '/table16_04',
      name: 'table16_04',
      component: () => import('../views/TableView16_04.vue')
    },
    {
      path: '/table16_05',
      name: 'table16_05',
      component: () => import('../views/TableView16_05.vue')
    },
    {
      path: '/table16_06',
      name: 'table16_06',
      component: () => import('../views/TableView16_06.vue')
    },
    {
      path: '/table16_07',
      name: 'table16_07',
      component: () => import('../views/TableView16_07.vue')
    },
    {
      path: '/table16_08',
      name: 'table16_08',
      component: () => import('../views/TableView16_08.vue')
    },
    {
      path: '/table16_09',
      name: 'table16_09',
      component: () => import('../views/TableView16_09.vue')
    },
    {
      path: '/table16_10',
      name: 'table16_10',
      component: () => import('../views/TableView16_10.vue')
    },
    {
      path: '/table16_11',
      name: 'table16_11',
      component: () => import('../views/TableView16_11.vue')
    },
    {
      path: '/table16_12',
      name: 'table16_12',
      component: () => import('../views/TableView16_12.vue')
    },
    {
      path: '/table16_13',
      name: 'table16_13',
      component: () => import('../views/TableView16_13.vue')
    },
    {
      path: '/table16_14',
      name: 'table16_14',
      component: () => import('../views/TableView16_14.vue')
    },
    {
      path: '/table17',
      name: 'table17',
      component: () => import('../views/TableView17.vue')
    },
    {
      path: '/calendar',
      name: 'calendar',
      component: () => import('../views/CalendarView.vue')
    }
  ],
})

export default router

📘编写展示入口 src\App.vue

 src\App.vue

<script setup>
import { RouterLink, RouterView } from 'vue-router'
import HelloWorld from './components/HelloWorld.vue'
</script>

<template>
  <header>
    <img alt="Vue logo" class="logo" src="@/assets/logo.svg" width="125" height="125" />

    <div class="wrapper">
      <HelloWorld msg="You did it!" />
      <nav>
        <RouterLink to="/">Progress</RouterLink>
        <RouterLink to="/tabs">Tabs</RouterLink>
        <RouterLink to="/accordion">Accordion</RouterLink>
        <RouterLink to="/timeline">Timeline</RouterLink>
        <RouterLink to="/backToTop">BackToTop</RouterLink>
        <RouterLink to="/notification">Notification</RouterLink>
        <RouterLink to="/card">Card</RouterLink>
        <RouterLink to="/infiniteScroll">InfiniteScroll</RouterLink>
        <RouterLink to="/switch">Switch</RouterLink>
        <RouterLink to="/sidebar">Sidebar</RouterLink>
        <RouterLink to="/breadcrumbs">Breadcrumbs</RouterLink>
        <RouterLink to="/masonryLayout">MasonryLayout</RouterLink>
        <RouterLink to="/rating">Rating</RouterLink>
        <RouterLink to="/datePicker">DatePicker</RouterLink>
        <RouterLink to="/colorPicker">ColorPicker</RouterLink>
        <RouterLink to="/rightClickMenu">RightClickMenu</RouterLink>
        <RouterLink to="/rangePicker">RangePicker</RouterLink>
        <RouterLink to="/navbar">Navbar</RouterLink>
        <RouterLink to="/formValidation">FormValidation</RouterLink>
        <RouterLink to="/copyToClipboard">CopyToClipboard</RouterLink>
        <RouterLink to="/clickAnimations">ClickAnimations</RouterLink>
        <RouterLink to="/thumbnailList">ThumbnailList</RouterLink>
        <RouterLink to="/keyboardShortcuts">KeyboardShortcuts</RouterLink>
        <RouterLink to="/commentSystem">CommentSystem</RouterLink>
        <RouterLink to="/qRCode">QRCode</RouterLink>
        <RouterLink to="/radioButton">RadioButton</RouterLink>
        <RouterLink to="/slider">Slider</RouterLink>
        <RouterLink to="/scrollAnimations">ScrollAnimations</RouterLink>
        <RouterLink to="/textInputView">TextInput</RouterLink>
        <RouterLink to="/divider">Divider</RouterLink>
        <RouterLink to="/checkbox">Checkbox</RouterLink>
        <RouterLink to="/tagInput">TagInput</RouterLink>
        <RouterLink to="/dropdownSelect">DropdownSelect</RouterLink>
        <RouterLink to="/list">List</RouterLink>
        <RouterLink to="/header">Header</RouterLink>
        <RouterLink to="/footer">Footer</RouterLink>
        <RouterLink to="/pagination">Pagination</RouterLink>
        <RouterLink to="/floatingActionButton">FloatingActionButton</RouterLink>
        <RouterLink to="/gridLayout">GridLayout</RouterLink>
        <RouterLink to="/passwordInput">PasswordInput</RouterLink>
        <RouterLink to="/flexbox">Flexbox</RouterLink>
        <RouterLink to="/modal">Modal</RouterLink>
        <RouterLink to="/richTextEditor">RichTextEditor</RouterLink>
        <RouterLink to="/timePickerView">TimePickerView</RouterLink>
        <RouterLink to="/multistepForm">MultistepFormView</RouterLink>
        <RouterLink to="/table1">Table1</RouterLink>
        <RouterLink to="/table2">Table2</RouterLink>
        <RouterLink to="/table3">Table3</RouterLink>
        <RouterLink to="/table4">Table4</RouterLink>
        <RouterLink to="/table5">Table5</RouterLink>
        <RouterLink to="/table6">Table6空状态</RouterLink>
        <RouterLink to="/table7">Table7空状态2</RouterLink>
        <RouterLink to="/table8">Table8基础加载状态</RouterLink>
        <RouterLink to="/table9">Table9自定义加载文本</RouterLink>
        <RouterLink to="/table10">Table10完全自定义加载内容</RouterLink>
        <RouterLink to="/table11">Table11加载结合分页</RouterLink>
        <RouterLink to="/table12">Table12启用列宽调整</RouterLink>
        <RouterLink to="/table12_02">table12_02自定义选择列宽度</RouterLink>
        <RouterLink to="/table14">table14 添加表头固定功能</RouterLink>
        <RouterLink to="/table14_01">table14_01</RouterLink>
        <RouterLink to="/table14_02">table14_02</RouterLink>
        <RouterLink to="/table14_03">table14_03</RouterLink>
        <RouterLink to="/table14_04">table14_04</RouterLink>
        <RouterLink to="/table14_05">table14_05</RouterLink>
        <RouterLink to="/table14_06">table14_06</RouterLink>
        <RouterLink to="/table14_07">table14_07</RouterLink>
        <RouterLink to="/table14_08">table14_08</RouterLink>
        <RouterLink to="/table14_09">table14_09</RouterLink>
        <RouterLink to="/table14_10">table14_10</RouterLink>
        <RouterLink to="/table14_11">table14_11</RouterLink>
        <RouterLink to="/table14_12">table14_12</RouterLink>
        <RouterLink to="/table14_13">table14_13</RouterLink>
        <RouterLink to="/table14_14">table14_14</RouterLink>
        <RouterLink to="/table15">table15 导出数据功能</RouterLink>
        <RouterLink to="/table15_01">table15_01</RouterLink>
        <RouterLink to="/table15_02">table15_02</RouterLink>
        <RouterLink to="/table15_03">table15_03</RouterLink>
        <RouterLink to="/table15_04">table15_04</RouterLink>
        <RouterLink to="/table15_05">table15_05</RouterLink>
        <RouterLink to="/table15_06">table15_06</RouterLink>
        <RouterLink to="/table15_07">table15_07</RouterLink>
        <RouterLink to="/table15_08">table15_08</RouterLink>
        <RouterLink to="/table15_09">table15_09</RouterLink>
        <RouterLink to="/table15_10">table15_10</RouterLink>
        <RouterLink to="/table15_11">table15_11</RouterLink>
        <RouterLink to="/table15_12">table15_12</RouterLink>
        <RouterLink to="/table15_13">table15_13</RouterLink>
        <RouterLink to="/table15_14">table15_14</RouterLink>
        <RouterLink to="/table16">table16添加行拖拽排序功能</RouterLink>
        <RouterLink to="/table16_01">table16_01</RouterLink>
        <RouterLink to="/table16_02">table16_02</RouterLink>
        <RouterLink to="/table16_03">table16_03</RouterLink>
        <RouterLink to="/table16_04">table16_04</RouterLink>
        <RouterLink to="/table16_05">table16_05</RouterLink>
        <RouterLink to="/table16_06">table16_06</RouterLink>
        <RouterLink to="/table16_07">table16_07</RouterLink>
        <RouterLink to="/table16_08">table16_08</RouterLink>
        <RouterLink to="/table16_09">table16_09</RouterLink>
        <RouterLink to="/table16_10">table16_10</RouterLink>
        <RouterLink to="/table16_11">table16_11</RouterLink>
        <RouterLink to="/table16_12">table16_12</RouterLink>
        <RouterLink to="/table16_13">table16_13</RouterLink>
        <RouterLink to="/table16_14">table16_14</RouterLink>
        <RouterLink to="/calendar">日历(Calendar)</RouterLink>
      </nav>
    </div>
  </header>
  <RouterView />
</template>

<style scoped>
header {
  line-height: 1.5;
  max-height: 100vh;
}

.logo {
  display: block;
  margin: 0 auto 2rem;
}

nav {
  width: 100%;
  font-size: 12px;
  text-align: center;
  margin-top: 2rem;
}

nav a.router-link-exact-active {
  color: var(--color-text);
}

nav a.router-link-exact-active:hover {
  background-color: transparent;
}

nav a {
  display: inline-block;
  padding: 0 1rem;
  border-left: 1px solid var(--color-border);
}

nav a:first-of-type {
  border: 0;
}

@media (min-width: 1024px) {
  header {
    display: flex;
    place-items: center;
    padding-right: calc(var(--section-gap) / 2);
  }

  .logo {
    margin: 0 2rem 0 0;
  }

  header .wrapper {
    display: flex;
    place-items: flex-start;
    flex-wrap: wrap;
  }

  nav {
    text-align: left;
    margin-left: -1rem;
    font-size: 1rem;

    padding: 1rem 0;
    margin-top: 1rem;
  }
}
</style>

📚页面效果

DeepSeek 助力 Vue3 开发:打造丝滑的日历(Calendar)

📚相关文章

   

———— 相 关 文 章 ————

   

  1. DeepSeek 助力 Vue 开发:打造丝滑的步骤条(Step bar)https://blog.csdn.net/qq_33650655/article/details/145560497

  2. DeepSeek 助力 Vue 开发:打造丝滑的进度条(Progress Bar)https://blog.csdn.net/qq_33650655/article/details/145577034

  3. DeepSeek 助力 Vue 开发:打造丝滑的标签页(Tabs)https://blog.csdn.net/qq_33650655/article/details/145587999

  4. DeepSeek 助力 Vue 开发:打造丝滑的折叠面板(Accordion)https://blog.csdn.net/qq_33650655/article/details/145590404

  5. DeepSeek 助力 Vue 开发:打造丝滑的时间线(Timeline )https://blog.csdn.net/qq_33650655/article/details/145597372

  6. DeepSeek 助力 Vue 开发:打造丝滑的返回顶部按钮(Back to Top)https://blog.csdn.net/qq_33650655/article/details/145615550

  7. DeepSeek 助力 Vue 开发:打造丝滑的通知栏(Notification Bar)https://blog.csdn.net/qq_33650655/article/details/145620055

  8. DeepSeek 助力 Vue 开发:打造丝滑的卡片(Card)https://blog.csdn.net/qq_33650655/article/details/145634564

  9. DeepSeek 助力 Vue 开发:打造丝滑的无限滚动(Infinite Scroll)https://blog.csdn.net/qq_33650655/article/details/145638452

  10. DeepSeek 助力 Vue 开发:打造丝滑的开关切换(Switch)https://blog.csdn.net/qq_33650655/article/details/145644151

  11. DeepSeek 助力 Vue 开发:打造丝滑的侧边栏(Sidebar)https://blog.csdn.net/qq_33650655/article/details/145654204

  12. DeepSeek 助力 Vue 开发:打造丝滑的面包屑导航(Breadcrumbs)https://blog.csdn.net/qq_33650655/article/details/145656895

  13. DeepSeek 助力 Vue 开发:打造丝滑的瀑布流布局(Masonry Layout)https://blog.csdn.net/qq_33650655/article/details/145663699

  14. DeepSeek 助力 Vue 开发:打造丝滑的评分组件(Rating)https://blog.csdn.net/qq_33650655/article/details/145664576

  15. DeepSeek 助力 Vue 开发:打造丝滑的日期选择器(Date Picker),未使用第三方插件 https://blog.csdn.net/qq_33650655/article/details/145673279

  16. DeepSeek 助力 Vue 开发:打造丝滑的颜色选择器(Color Picker)https://blog.csdn.net/qq_33650655/article/details/145689522

  17. DeepSeek 助力 Vue 开发:打造丝滑的右键菜单(RightClickMenu)https://blog.csdn.net/qq_33650655/article/details/145706658

  18. DeepSeek 助力 Vue 开发:打造丝滑的范围选择器(Range Picker)https://blog.csdn.net/qq_33650655/article/details/145713572

  19. DeepSeek 助力 Vue 开发:打造丝滑的导航栏(Navbar)https://blog.csdn.net/qq_33650655/article/details/145732421

  20. DeepSeek 助力 Vue 开发:打造丝滑的表单验证(Form Validation)https://blog.csdn.net/qq_33650655/article/details/145735582

  21. DeepSeek 助力 Vue 开发:打造丝滑的复制到剪贴板(Copy to Clipboard)https://blog.csdn.net/qq_33650655/article/details/145739569

  22. DeepSeek 助力 Vue 开发:打造丝滑的点击动画(Click Animations)https://blog.csdn.net/qq_33650655/article/details/145766184

  23. DeepSeek 助力 Vue 开发:打造丝滑的缩略图列表(Thumbnail List)https://blog.csdn.net/qq_33650655/article/details/145776679

  24. DeepSeek 助力 Vue 开发:打造丝滑的 键盘快捷键(Keyboard Shortcuts) https://blog.csdn.net/qq_33650655/article/details/145780227

  25. DeepSeek 助力 Vue 开发:打造丝滑的评论系统(Comment System)https://blog.csdn.net/qq_33650655/article/details/145781104

  26. DeepSeek 助力 Vue 开发:打造丝滑的二维码生成(QR Code)https://blog.csdn.net/qq_33650655/article/details/145797928

  27. DeepSeek 助力 Vue 开发:打造丝滑的单选按钮(Radio Button)https://blog.csdn.net/qq_33650655/article/details/145810620

  28. DeepSeek 助力 Vue 开发:打造丝滑的滑块(Slider)https://blog.csdn.net/qq_33650655/article/details/145817161

  29. DeepSeek 助力 Vue 开发:打造丝滑的滚动动画(Scroll Animations)https://blog.csdn.net/qq_33650655/article/details/145818571

  30. DeepSeek 助力 Vue 开发:打造丝滑的文本输入框(Text Input)https://blog.csdn.net/qq_33650655/article/details/145837003

  31. DeepSeek 助力 Vue 开发:打造丝滑的分割线(Divider)https://blog.csdn.net/qq_33650655/article/details/145849100

  32. DeepSeek 助力 Vue 开发:打造丝滑的 复选框(Checkbox)https://blog.csdn.net/qq_33650655/article/details/145855695

  33. DeepSeek 助力 Vue3 开发:打造丝滑的标签输入(Tag Input)https://blog.csdn.net/qq_33650655/article/details/145858574

  34. DeepSeek 助力 Vue3 开发:打造丝滑的下拉选择框(Dropdown Select)https://blog.csdn.net/qq_33650655/article/details/145861882

  35. DeepSeek 助力 Vue3 开发:打造丝滑的列表(List)https://blog.csdn.net/qq_33650655/article/details/145866384

  36. DeepSeek 助力 Vue3 开发:打造丝滑的页眉(Header)https://blog.csdn.net/qq_33650655/article/details/145885122

  37. DeepSeek 助力 Vue3 开发:打造丝滑的页脚(Footer)https://blog.csdn.net/qq_33650655/article/details/145886306

  38. DeepSeek 助力 Vue3 开发:打造丝滑的分页(Pagination)https://blog.csdn.net/qq_33650655/article/details/145886824

  39. DeepSeek 助力 Vue3 开发:打造丝滑的悬浮按钮(Floating Action Button)
    https://blog.csdn.net/qq_33650655/article/details/145888339

  40. DeepSeek 助力 Vue3 开发:打造丝滑的网格布局(Grid Layout)https://blog.csdn.net/qq_33650655/article/details/145893422

  41. DeepSeek 助力 Vue3 开发:打造丝滑的密码输入框(Password Input))https://blog.csdn.net/qq_33650655/article/details/145903079

  42. DeepSeek 助力 Vue3 开发:打造丝滑的弹性布局(Flexbox)https://blog.csdn.net/qq_33650655/article/details/145938677

  43. DeepSeek 助力 Vue3 开发:打造丝滑的模态框(Modal)https://blog.csdn.net/qq_33650655/article/details/145938939

  44. DeepSeek 助力 Vue3 开发:打造丝滑的时间选择器(Time Picker)https://blog.csdn.net/qq_33650655/article/details/145939053

  45. DeepSeek 助力 Vue3 开发:打造丝滑的表格(Table)示例1:基础表格 https://blog.csdn.net/qq_33650655/article/details/145939144

  46. DeepSeek 助力 Vue3 开发:打造丝滑的表格(Table)示例2: 分页和排序 https://blog.csdn.net/qq_33650655/article/details/146025347

  47. DeepSeek 助力 Vue3 开发:打造丝滑的表格(Table)示例3: 行选择 https://blog.csdn.net/qq_33650655/article/details/146025478

  48. DeepSeek 助力 Vue3 开发:打造丝滑的表格(Table)示例4: 自定义插槽 https://blog.csdn.net/qq_33650655/article/details/146025513

  49. DeepSeek 助力 Vue3 开发:打造丝滑的表格(Table)示例5: 搜索和过滤 https://blog.csdn.net/qq_33650655/article/details/146025532

  50. DeepSeek 助力 Vue3 开发:打造丝滑的表格(Table)之功能优化,添加表格空状态提示 https://blog.csdn.net/qq_33650655/article/details/146042249

  51. DeepSeek 助力 Vue3 开发:打造丝滑的表格(Table)之功能优化,添加表格空状态提示,带插图的空状态,Table7空状态2 https://blog.csdn.net/qq_33650655/article/details/146046044

  52. DeepSeek 助力 Vue3 开发:打造丝滑的表格(Table)之功能优化,基础加载状态,Table8基础加载状态 https://blog.csdn.net/qq_33650655/article/details/146049283

  53. DeepSeek 助力 Vue3 开发:打造丝滑的表格(Table)之功能优化,自定义加载文本,Table9自定义加载文本https://blog.csdn.net/qq_33650655/article/details/146049592

  54. DeepSeek 助力 Vue3 开发:打造丝滑的表格(Table)之功能优化,完全自定义加载内容,Table10完全自定义加载内容 https://blog.csdn.net/qq_33650655/article/details/146049663

  55. DeepSeek 助力 Vue3 开发:打造丝滑的表格(Table)之功能优化,加载结合分页 ,Table11加载结合分页 https://blog.csdn.net/qq_33650655/article/details/146049727

  56. DeepSeek 助力 Vue3 开发:打造丝滑的表格(Table)之功能优化,添加列宽调整功能Table12 https://blog.csdn.net/qq_33650655/article/details/146139452

  57. DeepSeek 助力 Vue3 开发:打造丝滑的表格(Table)之添加列宽调整功能,示例Table14基础固定表头示例https://blog.csdn.net/qq_33650655/article/details/146166033

  58. DeepSeek 助力 Vue3 开发:打造丝滑的表格(Table)之添加列宽调整功能,示例Table14_01基础固定表头示例 https://blog.csdn.net/qq_33650655/article/details/146162035

  59. DeepSeek 助力 Vue3 开发:打造丝滑的表格(Table)之添加列宽调整功能,示例Table14_02带边框和斑马纹的固定表头表格 https://blog.csdn.net/qq_33650655/article/details/146162045

  60. DeepSeek 助力 Vue3 开发:打造丝滑的表格(Table)之添加列宽调整功能,示例Table14_03可调整列宽的固定表头表格 https://blog.csdn.net/qq_33650655/article/details/146162057

  61. DeepSeek 助力 Vue3 开发:打造丝滑的表格(Table)之添加列宽调整功能,示例Table14_04带选择框的固定表头表格 https://blog.csdn.net/qq_33650655/article/details/146162076

  62. DeepSeek 助力 Vue3 开发:打造丝滑的表格(Table)之添加列宽调整功能,示例Table14_05可排序的固定表头表格 https://blog.csdn.net/qq_33650655/article/details/146162098

  63. DeepSeek 助力 Vue3 开发:打造丝滑的表格(Table)之添加列宽调整功能,示例Table14_06带搜索功能的固定表头表格 https://blog.csdn.net/qq_33650655/article/details/146162127

  64. DeepSeek 助力 Vue3 开发:打造丝滑的表格(Table)之添加列宽调整功能,示例Table14_07带分页的固定表头表格 https://blog.csdn.net/qq_33650655/article/details/146162135

  65. DeepSeek 助力 Vue3 开发:打造丝滑的表格(Table)之添加列宽调整功能,示例Table14_08带加载状态的固定表头表格 https://blog.csdn.net/qq_33650655/article/details/146162142

  66. DeepSeek 助力 Vue3 开发:打造丝滑的表格(Table)之添加列宽调整功能,示例Table14_09自定义单元格的固定表头表格 https://blog.csdn.net/qq_33650655/article/details/146162151

  67. DeepSeek 助力 Vue3 开发:打造丝滑的表格(Table)之添加列宽调整功能,示例Table14_10空状态的固定表头表格 https://blog.csdn.net/qq_33650655/article/details/146162165

  68. DeepSeek 助力 Vue3 开发:打造丝滑的表格(Table)之添加列宽调整功能,示例Table14_11多功能组合的固定表头表格 https://blog.csdn.net/qq_33650655/article/details/146162175

  69. DeepSeek 助力 Vue3 开发:打造丝滑的表格(Table)之添加列宽调整功能,示例Table14_12自定义表头的固定表头表格 https://blog.csdn.net/qq_33650655/article/details/146162186

  70. DeepSeek 助力 Vue3 开发:打造丝滑的表格(Table)之添加列宽调整功能,示例Table14_13可展开行的固定表头表格 https://blog.csdn.net/qq_33650655/article/details/146162201

  71. DeepSeek 助力 Vue3 开发:打造丝滑的表格(Table)之添加列宽调整功能,示例Table14_14树形数据的固定表头表格 https://blog.csdn.net/qq_33650655/article/details/146162213

  72. DeepSeek 助力 Vue3 开发:打造丝滑的表格(Table)之添加导出数据功能 https://blog.csdn.net/qq_33650655/article/details/146329292

  73. DeepSeek 助力 Vue3 开发:打造丝滑的表格(Table)之添加导出数据功能示例1,TableView15_01基础导出功能示例 https://blog.csdn.net/qq_33650655/article/details/146349203

  74. DeepSeek 助力 Vue3 开发:打造丝滑的表格(Table)之添加导出数据功能示例2,TableView15_02导出为CSV格式示例 https://blog.csdn.net/qq_33650655/article/details/146350878

  75. DeepSeek 助力 Vue3 开发:打造丝滑的表格(Table)之添加导出数据功能示例3,TableView15_03导出全部数据示例 https://blog.csdn.net/qq_33650655/article/details/146351008

  76. DeepSeek 助力 Vue3 开发:打造丝滑的表格(Table)之添加导出数据功能示例4,TableView15_04导出当前页数据示例 https://blog.csdn.net/qq_33650655/article/details/146382664

  77. DeepSeek 助力 Vue3 开发:打造丝滑的表格(Table)之添加导出数据功能示例5,TableView15_05自定义导出按钮文本示例 https://blog.csdn.net/qq_33650655/article/details/146383279

  78. DeepSeek 助力 Vue3 开发:打造丝滑的表格(Table)之添加导出数据功能示例6,TableView15_06自定义导出文件名示例 https://blog.csdn.net/qq_33650655/article/details/146383261

  79. DeepSeek 助力 Vue3 开发:打造丝滑的表格(Table)之添加导出数据功能示例7,TableView15_07带边框和斑马纹的导出表格示例 https://blog.csdn.net/qq_33650655/article/details/146351137

  80. DeepSeek 助力 Vue3 开发:打造丝滑的表格(Table)之添加导出数据功能示例8,TableView15_08带选择框的导出表格示例 https://blog.csdn.net/qq_33650655/article/details/146351159

  81. DeepSeek 助力 Vue3 开发:打造丝滑的表格(Table)之添加导出数据功能示例9,TableView15_09带排序的导出表格示例 https://blog.csdn.net/qq_33650655/article/details/146351181

  82. DeepSeek 助力 Vue3 开发:打造丝滑的表格(Table)之添加导出数据功能示例10,TableView15_10带搜索的导出表格示例 https://blog.csdn.net/qq_33650655/article/details/146351196

  83. DeepSeek 助力 Vue3 开发:打造丝滑的表格(Table)之添加导出数据功能示例11,TableView15_11带分页的导出表格示例 https://blog.csdn.net/qq_33650655/article/details/146351224

  84. DeepSeek 助力 Vue3 开发:打造丝滑的表格(Table)之添加导出数据功能示例12,TableView15_12固定表头的导出表格示例 https://blog.csdn.net/qq_33650655/article/details/146351254

  85. DeepSeek 助力 Vue3 开发:打造丝滑的表格(Table)之添加导出数据功能示例13,TableView15_13可调整列宽的导出表格示例 https://blog.csdn.net/qq_33650655/article/details/146351271

  86. DeepSeek 助力 Vue3 开发:打造丝滑的表格(Table)之添加导出数据功能示例14,TableView15_14多功能组合的导出表格示例 https://blog.csdn.net/qq_33650655/article/details/146351297

  87. DeepSeek 助力 Vue3 开发:打造丝滑的表格(Table)之添加行拖拽排序功能 https://blog.csdn.net/qq_33650655/article/details/146351051

  88. DeepSeek 助力 Vue3 开发:打造丝滑的表格(Table)之添加行拖拽排序功能示例1,TableView16_01.vue 基础行拖拽排序示例 https://blog.csdn.net/qq_33650655/article/details/146516134

  89. DeepSeek 助力 Vue3 开发:打造丝滑的表格(Table)之添加行拖拽排序功能示例2,TableView16_02.vue 拖拽视觉反馈示例 https://blog.csdn.net/qq_33650655/article/details/146351077

  90. DeepSeek 助力 Vue3 开发:打造丝滑的表格(Table)之添加行拖拽排序功能示例3,TableView16_03 拖拽视觉反馈示例 https://blog.csdn.net/qq_33650655/article/details/146517501

  91. DeepSeek 助力 Vue3 开发:打造丝滑的表格(Table)之添加行拖拽排序功能示例4,TableView16_04 跨表格拖拽示例 https://blog.csdn.net/qq_33650655/article/details/146517613

  92. DeepSeek 助力 Vue3 开发:打造丝滑的表格(Table)之添加行拖拽排序功能示例5,TableView16_05 树形表格拖拽排序 https://blog.csdn.net/qq_33650655/article/details/146517619

  93. DeepSeek 助力 Vue3 开发:打造丝滑的表格(Table)之添加行拖拽排序功能示例6,TableView16_06 分页表格拖拽排序 https://blog.csdn.net/qq_33650655/article/details/146517627

  94. DeepSeek 助力 Vue3 开发:打造丝滑的表格(Table)之添加行拖拽排序功能示例7,TableView16_07 列拖拽排序示例 https://blog.csdn.net/qq_33650655/article/details/146351099

  95. DeepSeek 助力 Vue3 开发:打造丝滑的表格(Table)之添加行拖拽排序功能示例8,TableView16_08 筛选状态拖拽排序 https://blog.csdn.net/qq_33650655/article/details/146545632

  96. DeepSeek 助力 Vue3 开发:打造丝滑的表格(Table)之添加行拖拽排序功能示例9,TableView16_09 嵌套表格拖拽排序 https://blog.csdn.net/qq_33650655/article/details/146545641

  97. DeepSeek 助力 Vue3 开发:打造丝滑的表格(Table)之添加行拖拽排序功能示例10,TableView16_10 虚拟滚动拖拽示例 https://blog.csdn.net/qq_33650655/article/details/146545647

  98. DeepSeek 助力 Vue3 开发:打造丝滑的表格(Table)之添加行拖拽排序功能示例11,TableView16_11 拖拽与行编辑结合示例 https://blog.csdn.net/qq_33650655/article/details/146545654

  99. DeepSeek 助力 Vue3 开发:打造丝滑的表格(Table)之添加行拖拽排序功能示例12,TableView16_12 拖拽动画示例 https://blog.csdn.net/qq_33650655/article/details/146545665

  100. DeepSeek 助力 Vue3 开发:打造丝滑的表格(Table)之添加行拖拽排序功能示例13,TableView16_13 键盘辅助拖拽示例 https://blog.csdn.net/qq_33650655/article/details/146794579

  101. DeepSeek 助力 Vue3 开发:打造丝滑的表格(Table)之添加行拖拽排序功能示例14,TableView16_14 拖拽自动保存示例 https://blog.csdn.net/qq_33650655/article/details/146795055

到此这篇文章就介绍到这了,更多精彩内容请关注本人以前的文章或继续浏览下面的文章,创作不易,如果能帮助到大家,希望大家多多支持宝码香车~💕,若转载本文,一定注明本文链接。


整理不易,点赞关注宝码香车

更多专栏订阅推荐:
👍 html+css+js 绚丽效果
💕 vue
✈️ Electron
⭐️ js
📝 字符串
✍️ 时间对象(Date())操作

Logo

欢迎加入DeepSeek 技术社区。在这里,你可以找到志同道合的朋友,共同探索AI技术的奥秘。

更多推荐