原生html+js+jq+less 实现时间区间下拉弹窗选择器
html弹窗
less样式
.popupForm { display: none; width: 100%; height: 100%; position: fixed; bottom: 0; left: 0; background-color: #57575748; .pop-box { position: absolute; bottom: 0; left: 0; height: auto; width: 100%; border-radius: 0.625rem 0.625rem 0rem 0rem; background: #ffffff; padding: 1.25rem 0; } // 取消 .cancel { font-size: 0.75rem; color: #606266; position: absolute; top: 1rem; right: 1.375rem; } .title { font-size: 1rem; color: #3d3d3d; text-align: center; } // 时间选择器 .time-box { padding: 0.625rem 0; .time { font-size: 1rem; color: #606266; text-align: center; span { margin: 0 1.6875rem; padding: 0.1875rem 0.625rem; border-bottom: 0.0625rem solid #d8d8d8; font-size: 0.875rem; color: #909399; } .active { color: #1890ff; } } .time-list { height: 12.5rem; margin: 1.875rem 0; position: relative; box-shadow: inset 0 0.3125rem 0.625rem #d5d5d52e, inset 0 -0.3125rem 0.625rem #d5d5d52e; &::after { content: \"\"; position: absolute; top: 5rem; left: 0; width: 100%; height: 0.0625rem; background-color: #eaeaea; } &::before { content: \"\"; position: absolute; bottom: 5rem; left: 0; width: 100%; height: 0.0625rem; background-color: #eaeaea; } & > div { flex: 1; text-align: center; overflow-y: auto; &::-webkit-scrollbar { width: 0; height: 0; } .li { height: 2.5rem; font-size: 0.875rem; color: #606266; padding: 0.625rem 0; } } } .bottom { gap: 2.5rem; .reset { width: 7.875rem; height: 1.6875rem; border-radius: 2.125rem; border: 0.0625rem solid #c4302c; font-size: 0.875rem; color: #c4302c; } .confirm { width: 7.875rem; height: 1.6875rem; border-radius: 2.1875rem; background: linear-gradient(180deg, #eb140f 0%, #c70504 100%); font-size: 0.875rem; color: #ffffff; } } }}
js整体逻辑
$(() => { // 当前年份 const thisYear = new Date().getFullYear(); const ITEM_HEIGHT = 40; // 每个选项高度 // 滚动类型:0=开始时间,1=结束时间 let type = 0; let startTime = \"\"; //开始时间 let endTime = \"\"; //结束时间 // 存储滚动下标 const scrollValues = { startYear: 0, startMonth: 1, startDay: 1, endYear: 0, endMonth: 1, endDay: 1, }; // 缓存 DOM 元素 const $year = $(\".time-list .year\"); const $month = $(\".time-list .month\"); const $day = $(\".time-list .day\"); const $timeSpans = $(\".time-box .time span\"); // ========== 生成年份列表(100年)========== function renderYearList() { let html = \'\'; for (let i = 0; i < 100; i++) { html += `${thisYear - i}年`; } html += \'\'; $year.html(html); } // ========== 生成月份列表(1~12月)========== function renderMonthList() { let html = \'\'; for (let i = 1; i <= 12; i++) { html += `${i}月`; } html += \'\'; $month.html(html); } // ========== 获取某年某月的天数(month: 1~12)========== function getDaysInMonth(year, month) { return new Date(year, month, 0).getDate(); } // ========== 更新日列表(根据当前年月动态生成)========== function updateDayList() { const yearOffset = type === 0 ? scrollValues.startYear : scrollValues.endYear; const month = type === 0 ? scrollValues.startMonth : scrollValues.endMonth; const year = thisYear - yearOffset; const days = getDaysInMonth(year, month); const dayKey = type === 0 ? \"startDay\" : \"endDay\"; const currentDay = scrollValues[dayKey]; // 如果当前日超出该月最大天数,修正为最后一天 if (currentDay > days) { scrollValues[dayKey] = days; } // 生成日 HTML let html = \'\'; for (let i = 1; i <= days; i++) { html += `${i}日`; } html += \'\'; $day.html(html); // 滚动到当前日 $day.scrollTop((scrollValues[dayKey] - 1) * ITEM_HEIGHT); } // ========== 格式化为 YYYY-MM-DD 字符串 ========== function formatTime(yearOffset, month, day) { const y = thisYear - yearOffset; const m = month < 10 ? `0${month}` : month; const d = day { let isAnimating = false; $container.on(\"wheel\", function (e) { e.preventDefault(); if (isAnimating) return; const delta = e.originalEvent.deltaY > 0 ? 1 : -1; const current = $container.scrollTop(); const maxScroll = this.scrollHeight - this.clientHeight; const nextScroll = Math.max( 0, Math.min(maxScroll, current + delta * ITEM_HEIGHT) ); isAnimating = true; $container.animate({ scrollTop: nextScroll }, 200, () => { isAnimating = false; }); // 计算滚动索引 const index = Math.round(nextScroll / ITEM_HEIGHT); // 更新对应值 if ($container.is($year)) { scrollValues[`${type === 0 ? \"start\" : \"end\"}Year`] = index; } else if ($container.is($month)) { scrollValues[`${type === 0 ? \"start\" : \"end\"}Month`] = index + 1; } else if ($container.is($day)) { scrollValues[`${type === 0 ? \"start\" : \"end\"}Day`] = index + 1; } updateDisplay(); // 更新显示 updateDayList(); // 重新生成日(月或年变化时) }); }); } // ========== 切换时间类型(点击“开始/结束”)========== $timeSpans.parent().on(\"click\", \"span\", function () { type = $(this).index(); const values = [ scrollValues[`${type === 0 ? \"start\" : \"end\"}Year`], scrollValues[`${type === 0 ? \"start\" : \"end\"}Month`] - 1, scrollValues[`${type === 0 ? \"start\" : \"end\"}Day`] - 1, ]; $year.scrollTop(values[0] * ITEM_HEIGHT); $month.scrollTop(values[1] * ITEM_HEIGHT); $day.scrollTop(values[2] * ITEM_HEIGHT); }); // ========== 初始化 ========== $(function () { renderYearList(); renderMonthList(); updateDayList(); // 初始生成日 initWheel(); // 默认显示当前日期(可选) // $timeSpans.eq(0).text(formatTime(0, 1, 1)); // $timeSpans.eq(1).text(formatTime(0, 1, 1)); }); // ========== 确认时间 ========== window.confirmTime = function () { // 判断开始结束时间是否正确 console.log(startTime, endTime); if (startTime && endTime && startTime > endTime) { // message.error(\"结束时间不能小于开始时间\"); } else if (!startTime && endTime) { // message.error(\"请选择开始时间\"); } else if (startTime && !endTime) { // message.error(\"请选择结束时间\"); } else { // 关闭弹窗 请求接口 toggleForm(10); } }; // ========== 重置时间 ========== window.resetTime = function () { $(\".time-box .time\").html(\"开始时间至结束时间\"); Object.assign(scrollValues, { startYear: 0, startMonth: 1, startDay: 1, endYear: 0, endMonth: 1, endDay: 1, }); $(\".time-box .time span\").eq(0).click(); // 触发切换并滚动 };});
打开关闭弹窗
function toggleForm(type) { // console.log(type); $(`#popupForm${type}`).fadeToggle(200);}