多级关联列表预览

0 阅读3分钟

image.png


<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>论文目录 - 多级关联列表预览</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }

body {
  font-family: "Microsoft YaHei", "PingFang SC", sans-serif;
  background: #3C3F41;
  color: #CCC;
  height: 100vh;
  display: flex;
  flex-direction: column;
}

/* 顶部收起条 */
.collapse-bar {
  height: 24px;
  background: #2B2B2B;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  border-bottom: 1px solid #515151;
}
.collapse-bar::after {
  content: "";
  width: 36px;
  height: 4px;
  background: #666;
  border-radius: 2px;
}

/* 目录容器 */
.catalog-container {
  flex: 1;
  overflow-y: auto;
  padding: 4px 0 20px 0;
}
.catalog-container::-webkit-scrollbar { width: 6px; }
.catalog-container::-webkit-scrollbar-track { background: transparent; }
.catalog-container::-webkit-scrollbar-thumb { background: #555; border-radius: 3px; }

/* 章(标题2) */
.chapter-item {
  display: flex;
  align-items: center;
  height: 42px;
  padding: 0 16px 0 12px;
  cursor: pointer;
  user-select: none;
  transition: background 0.15s;
  position: relative;
}
.chapter-item:hover { background: #4a4d50; }
.chapter-item.selected { background: #4A6EDB; }
.chapter-item.selected .chapter-title { color: #FFF; }
.chapter-item.selected .arrow svg path { fill: #FFF; }

/* 箭头 */
.arrow {
  width: 16px;
  height: 16px;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: transform 0.2s ease;
  flex-shrink: 0;
}
.arrow.expanded { transform: rotate(90deg); }
.arrow.hidden { visibility: hidden; }
.arrow svg { width: 12px; height: 12px; }
.arrow svg path { fill: #AAA; transition: fill 0.15s; }

/* 章标题文字 */
.chapter-title {
  margin-left: 4px;
  font-size: 14px;
  font-weight: bold;
  color: #CCC;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  transition: color 0.15s;
}

/* 节(标题3) */
.section-item {
  display: flex;
  align-items: center;
  height: 36px;
  padding: 0 16px 0 48px;
  cursor: pointer;
  user-select: none;
  transition: background 0.15s;
}
.section-item:hover { background: #4a4d50; }
.section-item.selected { background: #4A6EDB; }
.section-item.selected .section-title { color: #FFF; }

.section-title {
  font-size: 13px;
  color: #999;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  transition: color 0.15s;
}

/* 子节点容器动画 */
.children-wrapper {
  overflow: hidden;
  transition: max-height 0.25s ease;
}
.children-wrapper.collapsed { max-height: 0 !important; }

/* 底部蓝色边框指示器(选中章时) */
.chapter-item.selected::after {
  content: "";
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  width: 3px;
  background: #6B9BFF;
  border-radius: 0 2px 2px 0;
}
</style>
</head>
<body>

<div class="collapse-bar" title="收起面板"></div>

<div class="catalog-container" id="catalog"></div>

<script>
// ==================== 数据定义 ====================
const catalogData = [
  {
    title: "前 言",
    showContent: false,
    sections: []
  },
  {
    title: "第1章 绪论",
    sections: [
      "1.1 研究背景",
      "1.2 研究目的与意义",
      "1.3 国内外研究现状",
      "1.4 研究内容与论文结构"
    ]
  },
  {
    title: "第2章 相关技术",
    sections: [
      "2.1 安卓平台开发技术",
      "2.2 蓝牙通信技术",
      "2.3 数据库存储技术(LitePal)",
      "2.4 图表显示数据(MPAndroidChart)",
      "2.5 屏幕适配方案(AutoSize)",
      "2.6 线程间通信机制(EventBus)",
      "2.7 本地数据存储技术(SharedPreferences)"
    ]
  },
  {
    title: "第3章 系统需求分析",
    sections: [
      "3.1 系统功能需求",
      "3.2 系统非功能需求",
      "3.3 系统用例分析"
    ]
  },
  {
    title: "第4章 系统设计",
    sections: [
      "4.1 系统总体架构设计",
      "4.2 数据库设计",
      "4.3 接口设计",
      "4.4 UI界面设计"
    ]
  },
  {
    title: "第5章 系统实现",
    sections: [
      "5.1 开发环境搭建",
      "5.2 核心功能实现",
      "5.3 蓝牙通信模块实现",
      "5.4 数据展示模块实现"
    ]
  },
  {
    title: "第6章 系统测试",
    sections: [
      "6.1 测试环境",
      "6.2 功能测试",
      "6.3 性能测试",
      "6.4 兼容性测试"
    ]
  },
  {
    title: "结 论",
    showContent: true,
    sections: []
  },
  {
    title: "参考文献",
    showContent: true,
    sections: []
  },
  {
    title: "致 谢",
    showContent: true,
    sections: []
  }
];

// ==================== 状态管理 ====================
const expandedSet = new Set();
let selectedId = null;

// 箭头SVG
const arrowSVG = `<svg viewBox="0 0 24 24"><path d="M8.59 16.59L13.17 12 8.59 7.41 10 6l6 6-6 6z"/></svg>`;

// ==================== 渲染 ====================
function render() {
  const container = document.getElementById("catalog");
  container.innerHTML = "";

  catalogData.forEach((chapter, chapterIdx) => {
    const hasChildren = chapter.sections.length > 0;
    const isExpanded = expandedSet.has(chapterIdx);
    const chapterId = `ch-${chapterIdx}`;

    // 章节点
    const chapterEl = document.createElement("div");
    chapterEl.className = "chapter-item" + (selectedId === chapterId ? " selected" : "");
    chapterEl.innerHTML = `
      <div class="arrow ${hasChildren ? (isExpanded ? 'expanded' : '') : 'hidden'}">${arrowSVG}</div>
      <div class="chapter-title">${chapter.title}</div>
    `;

    chapterEl.addEventListener("click", () => {
      // 展开/收起
      if (hasChildren) {
        if (expandedSet.has(chapterIdx)) {
          expandedSet.delete(chapterIdx);
        } else {
          expandedSet.add(chapterIdx);
        }
      }
      // 选中
      selectedId = chapterId;
      render();
    });

    container.appendChild(chapterEl);

    // 子节点容器
    if (hasChildren) {
      const childrenWrapper = document.createElement("div");
      childrenWrapper.className = "children-wrapper" + (isExpanded ? "" : " collapsed");

      chapter.sections.forEach((section, secIdx) => {
        const sectionId = `sec-${chapterIdx}-${secIdx}`;
        const sectionEl = document.createElement("div");
        sectionEl.className = "section-item" + (selectedId === sectionId ? " selected" : "");
        sectionEl.innerHTML = `<div class="section-title">${section}</div>`;

        sectionEl.addEventListener("click", (e) => {
          e.stopPropagation();
          selectedId = sectionId;
          render();
        });

        childrenWrapper.appendChild(sectionEl);
      });

      // 设置展开高度
      if (isExpanded) {
        childrenWrapper.style.maxHeight = (chapter.sections.length * 36) + "px";
      }

      container.appendChild(childrenWrapper);
    }
  });
}

// 初始渲染
render();
</script>

</body>
</html>