DeepSeek+Vue:打造丝滑的日期选择器(Date Picker)

宝码香车 2025-03-05 11:02:11编程技术
193

在Web应用中,日期选择器(Date Picker)是一个常见且重要的组件。无论是日历应用、预订系统还是数据分析工具,日期选择器都扮演着不可或缺的角色。然而,实现一个高效、易用且美观的日期选择器并非易事。本文将介绍如何使用DeepSeek和Vue框架,打造一个丝滑流畅的日期选择器,为用户提供极致的交互体验。

📚页面效果

页面效果.gif

📚指令输入

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

功能要有,如下属性:

属性(Props)
  1. modelValue

    • 类型:Date | Date[] | null

    • 默认值:null

    • 说明:绑定的日期值(支持 v-model,范围选择时为数组)。

  2. minDate

    • 类型:Date | null

    • 默认值:null

    • 说明:最小可选日期,早于此日期的选项被禁用。

  3. maxDate

    • 类型:Date | null

    • 默认值:null

    • 说明:最大可选日期,晚于此日期的选项被禁用。

  4. format

    • 类型:string

    • 默认值:'YYYY-MM-DD'

    • 说明:日期显示格式(如 YYYY-MM-DD、MM/DD/YYYY)。

  5. disabled

    • 类型:boolean

    • 默认值:false

    • 说明:是否禁用组件。

  6. placeholder

    • 类型:string

    • 默认值:'请选择日期'

    • 说明:输入框占位符文本。

  7. firstDayOfWeek

    • 类型:number(0-6,0=周日)

    • 默认值:1(周一)

    • 说明:周起始日。

  8. showWeekNumbers

    • 类型:boolean

    • 默认值:false

    • 说明:是否显示周数。

  9. isRange

    • 类型:boolean

    • 默认值:false

    • 说明:是否为范围选择模式(modelValue 为 Date[])。

  10. locale

    • 类型:string | object

    • 默认值:'en'

    • 说明:本地化配置(语言、月份名等)。

  11. isInline

    • 类型:boolean

    • 默认值:false

    • 说明:是否内联显示日历面板(无需点击输入框)。

  12. className

    • 类型:string

    • 默认值:''

    • 说明:自定义容器类名。

  13. showConfirmButton

    • 类型:boolean

    • 默认值:true

    • 说明:是否显示确认按钮。

  14. confirmText

    • 类型:string

    • 默认值:'确认'

    • 说明:确认按钮文本。

  15. disableDate

    • 类型:(date: Date) => boolean

    • 默认值:() => false

    • 说明:动态禁用日期(返回 true 表示禁用)。

事件(Events)
  1. update:modelValue

    • 参数:Date | Date[] | null

    • 说明:选中日期变化时触发(用于 v-model 同步)。

  2. change

    • 参数:{ value: Date | Date[] | null, isValid: boolean }

    • 说明:日期变化时触发,附带有效性校验。

  3. confirm

    • 参数:Date | Date[] | null

    • 说明:点击确认按钮时触发。

  4. open

    • 参数:无

    • 说明:日历面板打开时触发。

  5. close

    • 参数:无

    • 说明:日历面板关闭时触发。

  6. invalid

    • 参数:{ reason: string }

    • 说明:用户输入或选择无效日期时触发。

你有更好的建议也可以添加,要注明。组件定义好后给出3个及以上的调用示例。

下面是现有目录

vueAndDeepseek/

├── 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/

│ │ ├── DatePicker/

│ │ └── 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

│ │ ├── DatePickerView.vue

│ │ └── AboutView.vue

│ ├── App.vue # 根组件

│ └── main.js # 应用入口

├── public/ # 公共资源目录

├── index.html # HTML 模板

├── package.json # 项目配置

├── vite.config.js # Vite 配置

└── node_modules/ # 依赖包目录

📘组件代码,src\components\DatePicker\DatePicker.vue

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

// Props 定义
const props = defineProps({
  modelValue: {
    type: [Date, Array, null],
    default: null
  },
  minDate: {
    type: Date,
    default: null
  },
  maxDate: {
    type: Date,
    default: null
  },
  format: {
    type: String,
    default: 'YYYY-MM-DD'
  },
  disabled: {
    type: Boolean,
    default: false
  },
  placeholder: {
    type: String,
    default: '请选择日期'
  },
  firstDayOfWeek: {
    type: Number,
    default: 1
  },
  showWeekNumbers: {
    type: Boolean,
    default: false
  },
  isRange: {
    type: Boolean,
    default: false
  },
  locale: {
    type: [String, Object],
    default: 'zh-CN'
  },
  isInline: {
    type: Boolean,
    default: false
  },
  className: {
    type: String,
    default: ''
  },
  showConfirmButton: {
    type: Boolean,
    default: true
  },
  confirmText: {
    type: String,
    default: '确认'
  },
  disableDate: {
    type: Function,
    default: () => false
  }
})

const emit = defineEmits(['update:modelValue', 'change', 'confirm', 'open', 'close', 'invalid'])

// 初始化状态
const currentDate = ref(new Date())
const selectedDate = ref(props.isRange ? [] : null)
const isOpen = ref(props.isInline)

// 格式化单个日期
const formatSingleDate = (date) => {
  if (!(date instanceof Date) || isNaN(date.getTime())) return ''
  const year = date.getFullYear()
  const month = String(date.getMonth() + 1).padStart(2, '0')
  const day = String(date.getDate()).padStart(2, '0')
  return props.format
    .replace('YYYY', year)
    .replace('MM', month)
    .replace('DD', day)
}

// 格式化显示日期
const formattedDate = computed(() => {
  if (!selectedDate.value) return ''
  if (Array.isArray(selectedDate.value)) {
    return selectedDate.value
      .map(date => date instanceof Date ? formatSingleDate(date) : '')
      .filter(Boolean)
      .join(' - ')
  }
  return formatSingleDate(selectedDate.value)
})

// 日历数据
const calendarDays = computed(() => {
  const year = currentDate.value.getFullYear()
  const month = currentDate.value.getMonth()
  const firstDay = new Date(year, month, 1)
  const lastDay = new Date(year, month + 1, 0)
  const days = []

  const firstDayOfWeek = firstDay.getDay()
  const prevMonthDays = (firstDayOfWeek - props.firstDayOfWeek + 7) % 7

  // 上月日期
  for (let i = prevMonthDays; i > 0; i--) {
    const date = new Date(year, month, 1 - i)
    days.push({
      date,
      isCurrentMonth: false,
      isDisabled: isDateDisabled(date)
    })
  }

  // 当月日期
  for (let i = 1; i <= lastDay.getDate(); i++) {
    const date = new Date(year, month, i)
    days.push({
      date,
      isCurrentMonth: true,
      isDisabled: isDateDisabled(date)
    })
  }

  // 下月日期
  const remainingDays = 42 - days.length
  for (let i = 1; i <= remainingDays; i++) {
    const date = new Date(year, month + 1, i)
    days.push({
      date,
      isCurrentMonth: false,
      isDisabled: isDateDisabled(date)
    })
  }

  return days
})

// 星期标题
const weekDays = computed(() => {
  const days = ['日', '一', '二', '三', '四', '五', '六']
  return [...days.slice(props.firstDayOfWeek), ...days.slice(0, props.firstDayOfWeek)]
})

// 判断日期是否禁用
const isDateDisabled = (date) => {
  if (!(date instanceof Date)) return true
  if (props.minDate && date < props.minDate) return true
  if (props.maxDate && date > props.maxDate) return true
  return props.disableDate(date)
}

// 选择日期
const selectDate = (day) => {
  if (!day.date || day.isDisabled) {
    emit('invalid', { reason: 'date disabled' })
    return
  }

  const newDate = new Date(day.date)

  if (props.isRange) {
    if (!Array.isArray(selectedDate.value)) {
      selectedDate.value = []
    }
    
    if (selectedDate.value.length === 0 || selectedDate.value.length === 2) {
      selectedDate.value = [newDate]
    } else {
      selectedDate.value = [selectedDate.value[0], newDate].sort((a, b) => a - b)
    }
  } else {
    selectedDate.value = newDate
  }

  emit('update:modelValue', selectedDate.value)
  emit('change', { value: selectedDate.value, isValid: true })
}

// 切换月份
const changeMonth = (delta) => {
  currentDate.value = new Date(
    currentDate.value.getFullYear(),
    currentDate.value.getMonth() + delta,
    1
  )
}

// 确认选择
const confirm = () => {
  emit('confirm', selectedDate.value)
  isOpen.value = false
  emit('close')
}

// 切换日历显示
const toggleCalendar = () => {
  if (props.disabled) return
  isOpen.value = !isOpen.value
  emit(isOpen.value ? 'open' : 'close')
}

// 监听数据变化
watch(() => props.modelValue, (newVal) => {
  if (props.isRange) {
    selectedDate.value = Array.isArray(newVal) 
      ? newVal.map(d => d instanceof Date ? new Date(d) : null)
      : []
  } else {
    selectedDate.value = newVal instanceof Date ? new Date(newVal) : null
  }
}, { immediate: true })
</script>

<template>
  <div :class="['date-picker', className]">
    <input
      type="text"
      :placeholder="placeholder"
      :value="formattedDate"
      @click="toggleCalendar"
      readonly
      :disabled="disabled"
    />
    
    <div v-if="isOpen || isInline" class="calendar">
      <div class="calendar-header">
        <button @click="changeMonth(-1)">&lt;</button>
        <span>{{ currentDate.getFullYear() }}年 {{ currentDate.getMonth() + 1 }}月</span>
        <button @click="changeMonth(1)">&gt;</button>
      </div>

      <div class="calendar-weeks">
        <div v-for="day in weekDays" :key="day" class="week-day">{{ day }}</div>
      </div>

      <div class="calendar-days">
        <div
          v-for="day in calendarDays"
          :key="day.date.getTime()"
          :class="[
            'calendar-day',
            {
              'is-current-month': day.isCurrentMonth,
              'is-disabled': day.isDisabled,
              'is-selected': selectedDate && (
                Array.isArray(selectedDate) 
                  ? selectedDate.some(d => d && d.getTime() === day.date.getTime())
                  : selectedDate.getTime() === day.date.getTime()
              )
            }
          ]"
          @click="selectDate(day)"
        >
          {{ day.date.getDate() }}
        </div>
      </div>

      <div v-if="showConfirmButton" class="calendar-footer">
        <button @click="confirm">{{ confirmText }}</button>
      </div>
    </div>
  </div>
</template>

<style scoped>
.date-picker {
  display: inline-block;
  position: relative;
}

input {
  padding: 8px;
  border: 1px solid #dcdfe6;
  border-radius: 4px;
  width: 200px;
  cursor: pointer;
}

.calendar {
  position: absolute;
  top: 100%;
  left: 0;
  margin-top: 5px;
  background: white;
  border: 1px solid #dcdfe6;
  border-radius: 4px;
  box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
  z-index: 1000;
}

.calendar-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 8px;
  border-bottom: 1px solid #ebeef5;
}

.calendar-weeks {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  text-align: center;
  border-bottom: 1px solid #ebeef5;
}

.week-day {
  padding: 8px;
  color: #606266;
}

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

.calendar-day {
  padding: 8px;
  text-align: center;
  cursor: pointer;
  color: #606266;
}

.calendar-day:hover:not(.is-disabled) {
  background-color: #f5f7fa;
}

.is-current-month {
  color: #303133;
}

.is-selected {
  background-color: #409eff;
  color: white;
}

.is-disabled {
  color: #c0c4cc;
  cursor: not-allowed;
  background-color: #f5f7fa;
}

.calendar-footer {
  padding: 8px;
  text-align: right;
  border-top: 1px solid #ebeef5;
}

button {
  padding: 6px 12px;
  background: #409eff;
  border: none;
  border-radius: 4px;
  color: white;
  cursor: pointer;
}

button:hover {
  background: #66b1ff;
}

.is-inline {
  position: static;
  margin-top: 0;
}
</style>

📘调用 src\views\DatePickerView.vue

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

// 初始化状态
const basicDate = ref(null)
const rangeDate = ref(null)
const disabledDate = ref(null)
const customDate = ref(null)
const inlineDate = ref(null)
const limitedDate = ref(null)

// 日期范围
const minDate = new Date('2024-01-01')
const maxDate = new Date('2024-12-31')

// 格式化函数
const formatDate = (date) => {
  if (!date) return '未选择'
  
  if (Array.isArray(date)) {
    if (!date.length) return '未选择'
    return date
      .map(d => {
        if (!d) return ''
        return d instanceof Date ? 
          d.toLocaleDateString('zh-CN', {
            year: 'numeric',
            month: '2-digit',
            day: '2-digit'
          }) : ''
      })
      .filter(Boolean)
      .join(' - ')
  }
  
  return date instanceof Date ? 
    date.toLocaleDateString('zh-CN', {
      year: 'numeric',
      month: '2-digit',
      day: '2-digit'
    }) : '未选择'
}

// 禁用周末
const isWeekend = (date) => {
  if (!(date instanceof Date)) return false
  const day = date.getDay()
  return day === 0 || day === 6
}

// 事件处理
const handleChange = ({ value, isValid }) => {
  console.log('日期变化:', formatDate(value), '是否有效:', isValid)
}

const handleConfirm = (date) => {
  alert(`确认选择:${formatDate(date)}`)
}
</script>

<template>
  <div class="datepicker-demo">
    <!-- 基础示例 -->
    <section class="demo-block">
      <h3>基础用法</h3>
      <DatePicker
        v-model="basicDate"
        placeholder="请选择日期"
        @change="handleChange"
      />
      <div class="demo-value">选中值: {{ formatDate(basicDate) }}</div>
    </section>

    <!-- 日期范围选择 -->
    <section class="demo-block">
      <h3>日期范围</h3>
      <DatePicker
        v-model="rangeDate"
        :is-range="true"
        placeholder="请选择日期范围"
        @change="handleChange"
      />
      <div class="demo-value">选中值: {{ formatDate(rangeDate) }}</div>
    </section>

    <!-- 禁用周末 -->
    <section class="demo-block">
      <h3>禁用周末</h3>
      <DatePicker
        v-model="disabledDate"
        :disable-date="isWeekend"
        placeholder="请选择工作日"
        @change="handleChange"
      />
      <div class="demo-value">选中值: {{ formatDate(disabledDate) }}</div>
    </section>

    <!-- 自定义格式 -->
    <section class="demo-block">
      <h3>自定义格式</h3>
      <DatePicker
        v-model="customDate"
        format="MM/DD/YYYY"
        placeholder="月/日/年"
        @change="handleChange"
      />
      <div class="demo-value">选中值: {{ formatDate(customDate) }}</div>
    </section>

    <!-- 设置日期范围 -->
    <section   style="">
      <h3>限制可选日期范围</h3>
      <DatePicker
        v-model="limitedDate"
        :min-date="minDate"
        :max-date="maxDate"
        placeholder="选择2024年日期"
        @change="handleChange"
        @confirm="handleConfirm"
      />
      <div class="demo-value">选中值: {{ formatDate(limitedDate) }}</div>
    </section>

    <!-- 内联显示 -->
    <section class="demo-block1">
      <h3>内联显示</h3>
      <DatePicker
          v-model="inlineDate"
          :is-inline="true"
          @change="handleChange"
      />
      <div class="demo-value">选中值: {{ formatDate(inlineDate) }}</div>
    </section>
  </div>
</template>

<style scoped>
.datepicker-demo {
  padding: 20px;
  max-width: 800px;
  margin: 0 auto;
}

.demo-block {
  margin-bottom: 30px;
  padding: 20px;
  border: 1px solid #ebeef5;
  border-radius: 4px;
  background-color: #fff;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
}


.demo-block1{
  margin-top: 300px;
}
h3 {
  margin-bottom: 15px;
  font-size: 18px;
  color: #333;
  font-weight: 500;
}

.demo-value {
  margin-top: 10px;
  padding: 10px;
  background: #f5f7fa;
  border-radius: 4px;
  font-size: 14px;
  color: #666;
  border: 1px solid #e4e7ed;
}
</style>

📚代码测试

正常

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

  • 添加路由

  • 页面展示入口

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

\router\index.js

import { createRouter, createWebHistory } from 'vue-router'


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')
    }
  ],
})

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"   src="https://blog.csdn.net/qq_33650655/article/details/@/assets/logo.svg"     />

    <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>
      </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和Vue框架,我们成功打造了一个高效、易用且美观的日期选择器。DeepSeek的强大功能和Vue的响应式机制,使得日期选择器在用户体验上达到了新的高度。无论是日期的实时预览、精确的日期选择还是自定义日期范围的设置,都得到了完美的实现。希望本文的介绍能够为开发者提供有价值的参考,助力大家在Web应用开发中实现更加出色的日期选择功能。

DeepSeek Vue 日期选择器 date picker
THE END
蜜芽
故事不长,也不难讲,四字概括,毫无意义。

相关推荐

DeepSeek一体机爆火:单机价飙至200W,它为啥这么火?
​2025年开年,AI行业迎来了一场“算力革命”。在这场革命中,一个名为DeepSeek的国产大模型,以及由其驱动的“智算一体机”,成为了全球科技圈和资本市场的焦点。单机价格动...
2025-03-07 电脑知识
200

Manus是什么?Manus和DeepSeek有哪些区别?
继DeepSeek之后,中国AI产品Manus再次震撼全球科技界。Manus不仅展示了其在处理复杂任务方面的卓越能力,还为未来的人机协作模式提供了全新的可能性。本文ZHANID工具网将深入...
2025-03-06 新闻资讯
253

DeepSeek+Vue:打造丝滑的评论系统(Comment System)
在现代Web应用中,评论系统(Comment System)是促进用户互动和内容分享的重要工具。然而,传统的评论系统实现方式往往缺乏灵活性和智能化。本文将介绍如何结合DeepSeek和Vue框...
2025-03-06 编程技术
208

DeepSeek+Vue:打造丝滑的二维码生成(QR Code)
二维码(QR Code)生成功能越来越受到开发者和用户的青睐。无论是用于分享链接、支付信息还是其他数据,二维码都能提供便捷的解决方案。然而,传统的二维码生成实现方式往往缺乏...
2025-03-06 编程技术
218

DeepSeek+Vue:打造丝滑的缩略图列表(Thumbnail List)
​在现代Web应用中,缩略图列表(Thumbnail List)是展示图片、视频等多媒体内容的重要方式。然而,传统的缩略图列表实现方式往往缺乏灵活性和交互性。本文将介绍如何结合DeepS...
2025-03-06 编程技术
199

DeepSeek+Vue:打造丝滑的键盘快捷键(Keyboard Shortcuts)
在现代Web应用中,键盘快捷键(Keyboard Shortcuts)是提升用户体验和操作效率的重要手段。然而,传统的键盘快捷键实现方式往往缺乏灵活性和智能化。本文将介绍如何结合DeepSee...
2025-03-06 编程技术
220