
DeepSeek 助力 Vue3 开发:打造丝滑的日历(Calendar)
DeepSeek - V3 - 0324是一款性能全面、特色鲜明的国产开源大模型,在逻辑推理、代码生成和中文创意内容方面表现出色,为各类用户提供了实用的AI助手
前言:哈喽,大家好,今天给大家分享一篇文章!并提供具体代码帮助大家深入理解,彻底掌握!创作不易,如果能帮助到大家或者给大家一些灵感和启发,欢迎收藏+关注哦 💕
目录
📚📗📕📘📖🕮💡📝🗂️✍️🛠️💻🚀🎉🏗️🌐🖼️🔗📊👉🔖⚠️🌟🔐⬇️·正文开始
⬇️·🎥😊🎓📩😺🌈🤝🤖📜📋🔍✅🧰❓📄📢📈 🙋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页面 https://chat.deepseek.com/
输入指令
已经创建好了一个基于Vue3的组合式API的项目(Composition API),并能正常运行起来,请帮我用 Vue3的组合式API(Composition API) 生成一个 日历(Calendar) 的功能组件,所有代码都保存在components/Calendar 下的文件夹中。功能组件的script标签中只有setup属性,使用普通 JavaScript 实现,不使用TypeScript。
功能要有,如下属性:
属性
- 日期相关
currentDate
:当前显示的日期,可用于初始化日历显示的月份和年份。minDate
:可选择的最小日期,限制用户选择范围。maxDate
:可选择的最大日期,限制用户选择范围。selectedDates
:已选中的日期,支持多选时可传入数组。
- 显示相关
showWeekNumbers
:是否显示周数。weekStartDay
:一周的起始日,如 0 表示周日,1 表示周一。showHeader
:是否显示日历头部,包含年月切换等操作。showTodayButton
:是否显示返回今日的按钮。
- 国际化相关
locale
:指定日历的语言环境,用于显示不同语言的月份和星期名称。
- 样式相关
theme
:指定日历的主题,如亮色、暗色。cellSize
:日历单元格的大小。
事件
- 日期选择
date-select
:当用户选择日期时触发,返回选中的日期。date-range-select
:当用户选择日期范围时触发,返回日期范围。
- 日历切换
month-change
:当用户切换月份时触发,返回当前显示的月份和年份。year-change
:当用户切换年份时触发,返回当前显示的年份。
- 其他
today-click
:当用户点击返回今日按钮时触发。
其他建议
- 性能优化:在渲染日历数据时,可采用虚拟列表技术,减少不必要的 DOM 渲染。
- 无障碍支持:确保日历组件支持键盘导航和屏幕阅读器,提高可用性。
- 自定义插槽:提供一些自定义插槽,让用户可以自定义日历的头部、日期单元格等部分。
- 动画效果:为日历的切换和选择操作添加一些动画效果,提升用户体验。
- 响应式设计:确保日历在不同屏幕尺寸下都能正常显示和使用。
你有更好的建议也可以添加,要注明。组件定义好后给出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"><</button>
<h2>{{ monthYearLabel }}</h2>
<button @click="nextMonth">></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个调用示例:
- 基本使用
<template>
<Calendar
@date-select="handleDateSelect"
/>
</template>
<script setup>
import Calendar from '@/components/Calendar/Calendar.vue'
const handleDateSelect = (date) => {
console.log('Selected date:', date)
}
</script>
- 多选日期
<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>
- 日期范围选择
<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>
- 自定义显示设置
<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>
- 带日期限制
<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>
组件特点说明:
- 使用组合式API实现,所有逻辑都在setup中组织
- 支持多种日期选择模式(单选、多选、范围选择)
- 完整的国际化支持
- 响应式布局,自动适应容器宽度
- 支持键盘导航(可通过添加键盘事件处理器扩展)
- 提供多个插槽(header、date-cell)用于自定义内容
- 内置主题系统,支持轻松扩展新主题
- 完善的日期验证逻辑
- 性能优化:使用计算属性缓存数据,减少重复计算
可以根据实际需求添加更多功能,如:
- 日期标记功能(节假日、特殊日期)
- 更强大的键盘导航支持
- 拖拽选择日期范围
- 周/月视图切换
- 自定义日期格式化函数等
📚代码测试
运行正常
📚上下月按钮不太好用,整理后主要代码
📘定义组件 \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"><</button>
<h2>{{ monthYearLabel }}</h2>
<button @click="nextMonth">></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
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
<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 助力 Vue 开发:打造丝滑的步骤条(Step bar)https://blog.csdn.net/qq_33650655/article/details/145560497
-
DeepSeek 助力 Vue 开发:打造丝滑的进度条(Progress Bar)https://blog.csdn.net/qq_33650655/article/details/145577034
-
DeepSeek 助力 Vue 开发:打造丝滑的标签页(Tabs)https://blog.csdn.net/qq_33650655/article/details/145587999
-
DeepSeek 助力 Vue 开发:打造丝滑的折叠面板(Accordion)https://blog.csdn.net/qq_33650655/article/details/145590404
-
DeepSeek 助力 Vue 开发:打造丝滑的时间线(Timeline )https://blog.csdn.net/qq_33650655/article/details/145597372
-
DeepSeek 助力 Vue 开发:打造丝滑的卡片(Card)https://blog.csdn.net/qq_33650655/article/details/145634564
-
DeepSeek 助力 Vue 开发:打造丝滑的开关切换(Switch)https://blog.csdn.net/qq_33650655/article/details/145644151
-
DeepSeek 助力 Vue 开发:打造丝滑的侧边栏(Sidebar)https://blog.csdn.net/qq_33650655/article/details/145654204
-
DeepSeek 助力 Vue 开发:打造丝滑的评分组件(Rating)https://blog.csdn.net/qq_33650655/article/details/145664576
-
DeepSeek 助力 Vue 开发:打造丝滑的导航栏(Navbar)https://blog.csdn.net/qq_33650655/article/details/145732421
-
DeepSeek 助力 Vue 开发:打造丝滑的二维码生成(QR Code)https://blog.csdn.net/qq_33650655/article/details/145797928
-
DeepSeek 助力 Vue 开发:打造丝滑的滑块(Slider)https://blog.csdn.net/qq_33650655/article/details/145817161
-
DeepSeek 助力 Vue 开发:打造丝滑的文本输入框(Text Input)https://blog.csdn.net/qq_33650655/article/details/145837003
-
DeepSeek 助力 Vue 开发:打造丝滑的分割线(Divider)https://blog.csdn.net/qq_33650655/article/details/145849100
-
DeepSeek 助力 Vue 开发:打造丝滑的 复选框(Checkbox)https://blog.csdn.net/qq_33650655/article/details/145855695
-
DeepSeek 助力 Vue3 开发:打造丝滑的标签输入(Tag Input)https://blog.csdn.net/qq_33650655/article/details/145858574
-
DeepSeek 助力 Vue3 开发:打造丝滑的列表(List)https://blog.csdn.net/qq_33650655/article/details/145866384
-
DeepSeek 助力 Vue3 开发:打造丝滑的页眉(Header)https://blog.csdn.net/qq_33650655/article/details/145885122
-
DeepSeek 助力 Vue3 开发:打造丝滑的页脚(Footer)https://blog.csdn.net/qq_33650655/article/details/145886306
-
DeepSeek 助力 Vue3 开发:打造丝滑的分页(Pagination)https://blog.csdn.net/qq_33650655/article/details/145886824
-
DeepSeek 助力 Vue3 开发:打造丝滑的弹性布局(Flexbox)https://blog.csdn.net/qq_33650655/article/details/145938677
-
DeepSeek 助力 Vue3 开发:打造丝滑的模态框(Modal)https://blog.csdn.net/qq_33650655/article/details/145938939
到此这篇文章就介绍到这了,更多精彩内容请关注本人以前的文章或继续浏览下面的文章,创作不易,如果能帮助到大家,希望大家多多支持宝码香车~💕,若转载本文,一定注明本文链接。
更多专栏订阅推荐:
👍 html+css+js 绚丽效果
💕 vue
✈️ Electron
⭐️ js
📝 字符串
✍️ 时间对象(Date())操作
更多推荐
所有评论(0)