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

如何使用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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 09:11:42