如何使用JavaScript或jQuery实现父元素的展开与折叠功能?
嘿,我之前刚好处理过类似的旧frameset文档升级需求,JS经验有限也没关系,咱们一步步来,下面是我整理的可行方案,都是实操性很强的步骤:
核心思路:替换Frameset为响应式布局
原来的frameset是把页面拆成固定分区,现在咱们要改成单页响应式结构,用JS动态加载主题内容到主区域,同时保留树形目录的交互逻辑。
第一步:重构页面基础结构,扔掉Frameset
先搭一个HTML5响应式模板,把目录和内容区域放在同一个页面里,用CSS Grid做基础布局,自动适配不同屏幕:
<!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> /* 桌面端双栏布局 */ .doc-container { display: grid; grid-template-columns: 280px 1fr; gap: 20px; min-height: 100vh; padding: 10px; } .toc-sidebar { border-right: 1px solid #eee; overflow-y: auto; padding-right: 10px; } .content-area { overflow-y: auto; padding-left: 10px; } /* 移动端自动切换为单栏 */ @media (max-width: 768px) { .doc-container { grid-template-columns: 1fr; } .toc-sidebar { border-right: none; border-bottom: 1px solid #eee; max-height: 200px; } } </style> </head> <body> <div class="doc-container"> <!-- 树形目录容器 --> <div class="toc-sidebar" id="tocContainer"></div> <!-- 主题内容加载容器 --> <div class="content-area" id="contentContainer"></div> </div> <script src="app.js"></script> </body> </html>
第二步:加载并渲染树形TOC
CMS生成的table-of-contents.htm应该是ul/li嵌套的树形结构,咱们用JS把它加载过来,同时给每个链接绑定点击事件,替换成动态加载内容:
// app.js 核心逻辑 async function loadTOC() { try { // 加载TOC页面 const response = await fetch('table-of-contents.htm'); const html = await response.text(); // 临时DOM解析TOC内容 const tempDiv = document.createElement('div'); tempDiv.innerHTML = html; const tocTree = tempDiv.querySelector('ul'); // 这里根据实际TOC结构调整选择器 if (tocTree) { // 给每个目录链接绑定点击事件 const links = tocTree.querySelectorAll('a'); links.forEach(link => { link.addEventListener('click', (e) => { e.preventDefault(); // 阻止默认跳转 const targetUrl = link.getAttribute('href'); loadContent(targetUrl, link); // 传入当前链接,用于高亮 }); }); // 把树形目录放到页面里 document.getElementById('tocContainer').appendChild(tocTree); } } catch (error) { console.error('目录加载失败:', error); document.getElementById('tocContainer').innerHTML = '<p>😅 目录加载出错了</p>'; } } // 加载主题内容到主区域 async function loadContent(url, activeLink) { try { const response = await fetch(url); const html = await response.text(); // 提取主题页面的核心内容(只取body里的部分,去掉html/head标签) const tempDiv = document.createElement('div'); tempDiv.innerHTML = html; const content = tempDiv.querySelector('body').innerHTML; // 渲染内容 const contentContainer = document.getElementById('contentContainer'); contentContainer.innerHTML = content; // 高亮当前选中的目录项 document.querySelectorAll('.toc-sidebar a.active').forEach(a => a.classList.remove('active')); activeLink.classList.add('active'); // 给内容做响应式适配(比如图片、表格) adjustContentResponsiveness(); } catch (error) { console.error('内容加载失败:', error); document.getElementById('contentContainer').innerHTML = '<p>😅 内容加载出错了</p>'; } } // 适配内容的响应式样式 function adjustContentResponsiveness() { // 图片自适应宽度 const images = document.querySelectorAll('#contentContainer img'); images.forEach(img => { img.style.maxWidth = '100%'; img.style.height = 'auto'; }); // 表格添加横向滚动 const tables = document.querySelectorAll('#contentContainer table'); tables.forEach(table => { const wrapper = document.createElement('div'); wrapper.style.overflowX = 'auto'; table.parentNode.insertBefore(wrapper, table); wrapper.appendChild(table); }); } // 页面加载完成后初始化 window.addEventListener('load', () => { loadTOC(); // 可选:默认加载第一个主题 // loadContent('first-topic.htm'); });
第三步:优化交互细节
- 给选中的目录项加高亮样式,在CSS里补充:
.toc-sidebar a.active { color: #007bff; font-weight: bold; text-decoration: none; }
- 移动端可以加个目录折叠按钮,节省空间:
在.toc-sidebar顶部加个按钮:
<button id="toggleToc" style="width:100%; margin-bottom:10px;">折叠目录</button>
然后在app.js里加事件:
document.getElementById('toggleToc').addEventListener('click', () => { const tocSidebar = document.querySelector('.toc-sidebar'); tocSidebar.classList.toggle('collapsed'); });
对应的CSS:
.toc-sidebar.collapsed { max-height: 50px; overflow: hidden; } .toc-sidebar.collapsed #toggleToc::after { content: ' 展开'; } .toc-sidebar #toggleToc::after { content: ' 折叠'; }
第四步:兼容旧内容的特殊情况
- 如果旧主题页面里有依赖frameset的JS(比如
parent.frames调用),可以加个全局垫片兼容:
// 模拟旧frames环境,避免报错 window.parent = { frames: { contentFrame: { document: document.getElementById('contentContainer') } } };
- 旧页面样式冲突的话,可以给内容容器加样式隔离:
#contentContainer * { box-sizing: border-box; margin: 0; padding: 0; /* 其他基础样式重置,根据实际情况调整 */ }
内容的提问来源于stack exchange,提问作者user172586
相关产品推荐
相关产品推荐

