You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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. 无视觉分组标识:原代码仅将同月份元素放在一起,但未添加月份标题,分组效果不直观。
  2. 月份顺序不可控:直接遍历对象键,浏览器可能不按1-12月的自然顺序输出,导致分组混乱。
  3. 逻辑冗余:先整体排序再按月内排序,重复操作且低效。

修正后的完整代码

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 00:45:53