JavaScript中按日期排序并分组列表项的问题求助
问题描述
开发Web应用时,需要将带日期标签的复选框列表按日期升序排序并按月分组。当前HTML结构固定,无法添加data属性,日期格式为「Monday, April 10th」。现有JavaScript代码的分组功能未达预期,需修正逻辑实现正确的排序与分组。
现有HTML结构
<ul class="faceted-filter-group-display__list"> <li class="faceted-filter-group-display__list-item"> <label class="faceted-filter-group-display__list-item-label"> <input class="faceted-filter-group-display__list-item-input" type="checkbox" value="Monday, April 10th" /> <svg class="faceted-filter-group-display__checkmark" width="14" height="14" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 14 14"> <path class="faceted-filter-group-display__checkmark-check" fill="none" d="M2.5 7L5.5 10L11.5 4"></path> </svg> <span class="faceted-filter-group-display__list-item-label-text">Monday, April 10th</span> </label> </li> <!-- Other list items ... --> </ul>
现有JavaScript代码
function sortLiElements() { console.log("Sorting li elements..."); const list = document.querySelector(".faceted-filter-group-display__list"); const liElements = Array.from( list.querySelectorAll(".faceted-filter-group-display__list-item") ); liElements.sort((a, b) => { const aText = a.querySelector( ".faceted-filter-group-display__list-item-label-text" ).textContent; const bText = b.querySelector( ".faceted-filter-group-display__list-item-label-text" ).textContent; const aDate = new Date(aText.split(", ")[1]); const bDate = new Date(bText.split(", ")[1]); return aDate - bDate; }); for (const li of liElements) { list.appendChild(li); } console.log("Sorting complete."); } console.log("Starting sorting process..."); sortLiElements(); console.log("Sorting process finished."); const ul = document.querySelector(".faceted-filter-group-display__list"); const liElements = Array.from( ul.querySelectorAll(".faceted-filter-group-display__list-item") ); console.log("Creating month collections..."); const monthCollections = { January: [], February: [], March: [], April: [], May: [], June: [], July: [], August: [], September: [], October: [], November: [], December: [], }; liElements.forEach((li) => { const dateText = li.querySelector( ".faceted-filter-group-display__list-item-label-text" ).textContent; const month = dateText.split(" ")[1]; // Get the month name monthCollections[month].push(li); }); console.log("Sorting dates within month collections..."); for (const month in monthCollections) { monthCollections[month].sort((a, b) => { const dateTextA = a.querySelector( ".faceted-filter-group-display__list-item-label-text" ).textContent; const dateTextB = b.querySelector( ".faceted-filter-group-display__list-item-label-text" ).textContent; const dateValueA = new Date(dateTextA.split(" ").slice(1).join(" ")); const dateValueB = new Date(dateTextB.split(" ").slice(1).join(" ")); if (dateValueA.getDate() !== dateValueB.getDate()) { return dateValueA.getDate() - dateValueB.getDate(); } else { return dateValueA - dateValueB; } }); console.log(`${month}: ${monthCollections[month].length} items`); } console.log("Clearing and re-appending sorted elements..."); ul.innerHTML = ""; const fragment = document.createDocumentFragment(); for (const month in monthCollections) { monthCollections[month].forEach((li) => fragment.appendChild(li)); } ul.appendChild(fragment); console.log("Re-appending complete.");
问题分析与修正方案
核心问题
- 无视觉分组标识:原代码仅将同月份元素放在一起,但未添加月份标题,分组效果不直观。
- 月份顺序不可控:直接遍历对象键,浏览器可能不按1-12月的自然顺序输出,导致分组混乱。
- 逻辑冗余:先整体排序再按月内排序,重复操作且低效。
修正后的完整代码
function sortAndGroupDates() { const list = document.querySelector(".faceted-filter-group-display__list"); const liElements = Array.from(list.querySelectorAll(".faceted-filter-group-display__list-item")); // 解析每个元素的日期信息,统一存储 const dateItems = liElements.map(li => { const dateText = li.querySelector(".faceted-filter-group-display__list-item-label-text").textContent; const datePart = dateText.split(", ")[1]; // 处理序数词(如10th→10),确保Date正确解析 const normalizedDatePart = datePart.replace(/(\d+)(st|nd|rd|th)/, "$1"); const dateObj = new Date(normalizedDatePart); return { element: li, date: dateObj, month: dateObj.toLocaleString('en-US', { month: 'long' }) }; }); // 按日期升序排序所有项 dateItems.sort((a, b) => a.date - b.date); // 按固定月份顺序分组,确保顺序正确 const monthOrder = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"]; const groupedByMonth = {}; monthOrder.forEach(month => groupedByMonth[month] = []); dateItems.forEach(item => { groupedByMonth[item.month].push(item.element); }); // 清空原列表,构建分组DOM list.innerHTML = ""; const fragment = document.createDocumentFragment(); monthOrder.forEach(month => { const items = groupedByMonth[month]; if (items.length === 0) return; // 添加月份标题 const monthHeader = document.createElement("li"); monthHeader.style.fontWeight = "bold"; monthHeader.style.padding = "8px 0"; monthHeader.textContent = month; fragment.appendChild(monthHeader); // 添加该月份的所有复选框项 items.forEach(li => fragment.appendChild(li)); }); list.appendChild(fragment); } // 执行排序分组 sortAndGroupDates();
关键优化点
- 日期解析鲁棒性:处理序数词格式,避免浏览器解析失败。
- 可靠的月份顺序:使用固定数组遍历,保证分组按1-12月自然顺序展示。
- 直观分组标识:添加月份标题,明确区分不同分组。
- 简化逻辑:合并解析、排序、分组流程,减少重复DOM操作,提升性能。
内容的提问来源于stack exchange,提问作者Saad Ullah Sajid
相关产品推荐
相关产品推荐

