当前位置: 首页 > news >正文

周选择日历组件

这是组件代码
下面展示一些 内联代码片

// A code block
<template><div class="week-picker"><div class="wp-header"><button class="nav" @click="prevMonth" aria-label="Previous month">‹</button><div class="title">{{ formatMonthYear(viewDate) }}</div><button class="nav" @click="nextMonth" aria-label="Next month">›</button></div><table class="wp-calendar"><thead><tr><th v-for="(d, i) in weekdayLabels" :key="i">{{ d }}</th></tr></thead><tbody><tr v-for="(week, wi) in weeks" :key="wi"@mouseenter="hoverWeekIndex = wi"@mouseleave="hoverWeekIndex = null"><td v-for="(day, di) in week" :key="di":class="cellClass(day, wi)"@click="onDayClick(day, wi)"><div class="date">{{ day.getDate() }}</div></td></tr></tbody></table><div class="wp-footer" v-if="showFooter"><div class="range">选中周:{{ selectedRangeText }}</div></div></div>
</template><script setup>import { ref, computed, watch } from 'vue'const props = defineProps({modelValue: { type: [String, Date], default: null },weekStartsOn: { type: Number, default: 1 }, // 0 = Sunday, 1 = MondayvalueType: { type: String, default: 'string' }, // emitted value type: 'string' | 'date'showFooter: { type: Boolean, default: false },})const emit = defineEmits(['update:modelValue', 'change'])function parseToDate(v) {if (!v) return nullif (v instanceof Date) return new Date(v.getFullYear(), v.getMonth(), v.getDate())const s = String(v)const m = s.match(/^(\d{4})-(\d{2})-(\d{2})/)if (m) return new Date(Number(m[1]), Number(m[2]) - 1, Number(m[3]))const d = new Date(s)if (!isNaN(d.getTime())) return new Date(d.getFullYear(), d.getMonth(), d.getDate())return null}function formatDateYYYYMMDD(d) {const y = d.getFullYear()const m = String(d.getMonth() + 1).padStart(2, '0')const day = String(d.getDate()).padStart(2, '0')return `${y}-${m}-${day}`}function startOfWeek(date, weekStartsOn) {const d = new Date(date.getFullYear(), date.getMonth(), date.getDate())const day = d.getDay()const diff = (day - weekStartsOn + 7) % 7d.setDate(d.getDate() - diff)d.setHours(0, 0, 0, 0)return d}function isSameDay(a, b) {return a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate()}function isSameWeek(a, b) {if (!a || !b) return falseconst sa = startOfWeek(a, props.weekStartsOn)const sb = startOfWeek(b, props.weekStartsOn)return isSameDay(sa, sb)}const today = new Date()const viewDate = ref(new Date(today.getFullYear(), today.getMonth(), 1))const internalSelectedStart = ref(props.modelValue? startOfWeek(parseToDate(props.modelValue), props.weekStartsOn): startOfWeek(today, props.weekStartsOn) // 默认选中当前周)// 同时触发一次默认值给父组件if (!props.modelValue) {let emitValue = internalSelectedStart.valueif (props.valueType === 'string') emitValue = formatDateYYYYMMDD(emitValue)emit('update:modelValue', emitValue)emit('change', emitValue)}watch(() => props.modelValue, (nv) => {internalSelectedStart.value = nv ? startOfWeek(parseToDate(nv), props.weekStartsOn) : null})const weekdayLabels = computed(() => {if (props.weekStartsOn === 1) {return ['一', '二', '三', '四', '五', '六', '日']}return ['日', '一', '二', '三', '四', '五', '六']})function getMonthMatrix(baseDate) {const firstOfMonth = new Date(baseDate.getFullYear(), baseDate.getMonth(), 1)const start = startOfWeek(firstOfMonth, props.weekStartsOn)const matrix = []for (let i = 0; i < 6; i++) {const week = []for (let j = 0; j < 7; j++) {const d = new Date(start)d.setDate(start.getDate() + i * 7 + j)week.push(d)}matrix.push(week)}return matrix}const weeks = computed(() => getMonthMatrix(viewDate.value))const hoverWeekIndex = ref(null)function cellClass(day, weekIndex) {const classes = {}classes['muted'] = day.getMonth() !== viewDate.value.getMonth()const weekStart = startOfWeek(weeks.value[weekIndex][0], props.weekStartsOn)classes['selected-week'] = internalSelectedStart.value ? isSameDay(weekStart, internalSelectedStart.value) : falseclasses['hover-week'] = hoverWeekIndex.value === weekIndexclasses['today'] = isSameDay(day, today)return classes}function onDayClick(day, weekIndex) {const weekStart = startOfWeek(day, props.weekStartsOn)internalSelectedStart.value = weekStartlet emitValue = weekStartif (props.valueType === 'string') emitValue = formatDateYYYYMMDD(weekStart)emit('update:modelValue', emitValue)emit('change', emitValue)}function prevMonth() {viewDate.value = new Date(viewDate.value.getFullYear(), viewDate.value.getMonth() - 1, 1)}function nextMonth() {viewDate.value = new Date(viewDate.value.getFullYear(), viewDate.value.getMonth() + 1, 1)}const selectedRangeText = computed(() => {if (!internalSelectedStart.value) return '—'const start = internalSelectedStart.valueconst end = new Date(start)end.setDate(start.getDate() + 6)return `${formatDateYYYYMMDD(start)} 至 ${formatDateYYYYMMDD(end)}`})function clear() {internalSelectedStart.value = nullemit('update:modelValue', null)emit('change', null)}function formatMonthYear(d) {return `${d.getFullYear()} 年 ${d.getMonth() + 1} 月`}</script><style scoped>.week-picker {width: 100%;padding: 8px;font-family: "Helvetica Neue", Arial, sans-serif;user-select: none;}.wp-header {display: flex;align-items: center;justify-content: space-between;margin-bottom: 6px;}.nav {border: none;background: transparent;font-size: 28px;cursor: pointer;padding: 4px 8px;}.title {font-weight: 600;}.wp-calendar {width: 100%;border-collapse: collapse;table-layout: fixed;}.wp-calendar th, .wp-calendar td {width: 14.2857%;text-align: center;padding: 6px 2px;}.wp-calendar thead th {font-weight: 600;font-size: 12px;color: #666;}.wp-calendar td {cursor: pointer;}.wp-calendar td .date {width: 28px;height: 28px;line-height: 28px;margin: 0 auto;}.wp-calendar td.muted {color: #bbb;}.wp-calendar td.today .date {background-color: #4E80EE;color: #fff;border-radius: 50%;}.wp-calendar td.hover-week {background: rgba(0, 122, 255, 0.06);}.wp-calendar td.hover-week:first-child {border-radius: 6px 0 0 6px;}.wp-calendar td.hover-week:last-child {border-radius: 0 6px 6px 0;}.wp-calendar td.selected-week {background: rgba(0, 122, 255, 0.12);}.wp-calendar td.selected-week:first-child {border-radius: 6px 0 0 6px;}.wp-calendar td.selected-week:last-child {border-radius: 0 6px 6px 0;}.wp-footer {display: flex;justify-content: space-between;align-items: center;margin-top: 8px;font-size: 13px;}.actions button {border: 1px solid #e6e6e6;background: #fff;padding: 4px 8px;border-radius: 4px;cursor: pointer;}
</style>

效果图:
在这里插入图片描述


文章转载自:

http://zUWi5knZ.nqyfm.cn
http://r4m5D7oa.nqyfm.cn
http://BaUq5CvQ.nqyfm.cn
http://pHB6VzS2.nqyfm.cn
http://SWqAclNo.nqyfm.cn
http://xe4LL1pL.nqyfm.cn
http://JndC1lpE.nqyfm.cn
http://3OscH6ha.nqyfm.cn
http://Dmm6ZAAM.nqyfm.cn
http://KNGrgzfN.nqyfm.cn
http://o4573VW2.nqyfm.cn
http://3PyXGBWN.nqyfm.cn
http://WmKJvotz.nqyfm.cn
http://pWdd1Fim.nqyfm.cn
http://Ce4ChNOO.nqyfm.cn
http://1brSKARR.nqyfm.cn
http://B48rTg1c.nqyfm.cn
http://p6mER4YB.nqyfm.cn
http://qq0nXUjU.nqyfm.cn
http://ebX2nOjG.nqyfm.cn
http://0rL1zaxV.nqyfm.cn
http://4mdJwgmc.nqyfm.cn
http://YMFVO0hE.nqyfm.cn
http://8ow5YrLT.nqyfm.cn
http://dynhYmkD.nqyfm.cn
http://XFbMH2Sq.nqyfm.cn
http://jC244zoW.nqyfm.cn
http://9LsL6RWl.nqyfm.cn
http://mQK7Yyoh.nqyfm.cn
http://bbg4tkTS.nqyfm.cn
http://www.dtcms.com/a/384935.html

相关文章:

  • Golang引用类型
  • Go的Gob编码介绍与使用指南
  • Golang语言入门篇001_Golang简介
  • Kafka消息队列进阶:发送策略与分区算法优化指南
  • 台积电生态工程深度解析:从晶圆厂到蜂巢的系统架构迁移
  • 机器学习-网络架构搜索
  • 邪修实战系列(5)
  • 突破限制:Melody远程音频管理新体验
  • 深入解析Seata:一站式分布式事务解决方案
  • static_cast:C++类型系统的“正经翻译官”
  • Python面试题及详细答案150道(126-135) -- 数据库交互篇
  • 【新书预告】《大模型应用开发》
  • MySQL 视图的创建与查看:从基础操作到核心技巧
  • 企业内容管理(ECM)软件推荐与应用解析
  • 利用postgres_proto和pgproto配合验证测试postgres协议
  • 联咏nt98568点亮sensor步骤
  • 大模型操作SQL查询Text2SQL
  • 风力发电乙级资质需要哪些人员配备
  • 【JavaScript】实现一个高精度的定时器
  • 无偏估计-
  • SQL-流程控制函数
  • TNNLS-2015《Linear-Time Subspace Clustering via Bipartite Graph Modeling》
  • 线性代数 · 行列式 | 子式 / 主子式 / 顺序主子式 / 余子式 / 代数余子式
  • LLM的MTP论文阅读
  • 软考-系统架构设计师 软件工程详细讲解
  • MATLAB 实现基于 GMM-HMM的语音识别系统
  • Day24_【深度学习(4)—PyTorch使用—张量的数值计算】
  • 2019年下半年 系统架构设计师 综合知识
  • C++类和对象详解(2);初识类的默认成员函数
  • AI智能体的应用前景