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

求助:如何让带折叠功能的目录在页面加载时自动展开当前章节

目录折叠功能:页面加载自动展开当前章节的修复方案

我在网页中使用层级目录,通过CSS为标记了toc-current-section类的当前章节(该类可能出现在目录任意层级)添加边框。为实现目录折叠功能,编写了对应的JavaScript脚本和CSS样式,但遇到页面加载时当前章节无法自动展开的问题。

最初尝试新增脚本逻辑,给对应元素添加faq-clicked类——虽然类成功添加,但目录仍处于折叠状态。排查后发现:原折叠脚本是为子级li元素而非ol元素切换faq-clicked类,修改为给o[t].firstElementChild切换该类后,问题得以解决。


HTML片段

<ol>
    ...
</ol>
<ol>
    <li><a href="#">Public Host Server</a>
        <ol class="toc-collapse-level">
            <li><a href="#">Host Server</a>
                <ol>
                    <li class="toc-current-section"><a href="#">Hyper-V Configuration</a>
                        <ol>
                            <li><a href="#s1">Host Network Settings and Status</a></li>
                            <li><a href="#s2">Disk and VM Configuration Locations</a></li>
                            <li><a href="#s3">Virtual Switch Configuration</a></li>
                            <li><a href="#s4">Installed Virtual Servers</a></li>
                            <li><a href="#s5">Web Servers and Reverse Proxy Server VM Network Adapter Settings</a></li>
                        </ol>
                    </li>
                </ol>
            </li>   
            <li>
                <ol>
                    <li><a>...</a>
                        <ol>
                            <li><a>...</a></li>
                            <li><a>...</a></li>
                            <li><a>...</a></li>
                        </ol>
                    </li>                 
                </ol>
            </li>
        </ol>
    </li>
</ol>
<ol>
    ...
</ol>

JavaScript脚本

(t => {
const e = "faq-list",
    n = "faq-clicked";

    function l(l, o) {
        const i = l.children;
        if (0 === i.length) return;
        for (let t of i)
            if (t.childElementCount < 2) return;
            let c = l.classList;
            if (c.length > 0 && !c.contains(e)) return;
            c.add(e);
            const s = t.createElement("span");
            let a = !1;
            s.className = "faq-button", s.innerText = "⊕", s.onclick = function() {
                a = !a, this.innerText = a ? "⊖" : "⊕";
                for (const t of l.children) t.classList.toggle(n, a)
            }, l.before(s);
            for (let t = 0; t < i.length; t++) {
                let e = i[t];
                e.id = "faq-" + (o ? o + "-" : "") + (t + 1);
                let l = e.firstElementChild;
                l.insertAdjacentHTML("beforeend", ` <span class="anchor"><a href="#${e.id}">#</a></span>`), location.hash === "#" + e.id && (e.scrollIntoView(), e.classList.add(n)), l.onclick = function(t) {
                e.classList.toggle(n)
            }
        }
    }

    // 新增:判断元素是否在视口内
    function isElementVisible(el) {
        var rect = el.getBoundingClientRect(),
            vWidth = window.innerWidth || document.documentElement.clientWidth,
            vHeight = window.innerHeight || document.documentElement.clientHeight,
            efp = function (x, y) {
                return document.elementFromPoint(x, y)
            };

        // 元素完全不在视口内返回false
        if (rect.right < 0 || rect.bottom < 0
            || rect.left > vWidth || rect.top > vHeight)
            return false;

        // 元素任意一个角在视口内则返回true
        return (
            el.contains(efp(rect.left, rect.top))
            || el.contains(efp(rect.right, rect.top))
            || el.contains(efp(rect.right, rect.bottom))
            || el.contains(efp(rect.left, rect.bottom))
        );
    }

    const o = t.querySelectorAll(["div", "main", "section", "article"].map((t => t + ":not(.footnotes) > ol")).join(","));

    for (let t = 0; t < o.length; t++) {
        l(o[t], o.length > 1 ? t + 1 : 0)
        if(isElementVisible(o[t])){

            // 获取一级ol元素
            tocSectionL1_ol = o[t].firstElementChild.childNodes[2];  

            // 获取一级ol下的li元素
            tocSectionL1_li = tocSectionL1_ol.firstElementChild;

            // 获取二级ol元素
            tocSectionL2_ol = tocSectionL1_li.childNodes[2];

            // 获取二级ol下的li元素
            tocSectionL2_li = tocSectionL2_ol.firstElementChild;

            // 获取li元素的类名
            tocSectionL1_li_class = tocSectionL1_li.className;
            tocSectionL2_li_class = tocSectionL2_li.className;

            // 检查是否有li包含当前章节类
            if((tocSectionL1_li_class || tocSectionL2_li_class) == "toc-current-section") {

                // 关键修复:给正确的元素切换折叠类
                o[t].firstElementChild.classList.toggle("faq-clicked");
            }
        }
    }
})(document);

CSS样式

.faq-button {
    cursor: pointer
}

.faq-list>li>:first-child {
    display: block;
    cursor: pointer;
    background: #fafafa;
    margin: -.5em;
    padding: .5em
}

.faq-list>:not(.faq-clicked)>* {
    display: none
}

.faq-button {
    float: right;
    margin-left: 1em
}

.faq-list .anchor {
    display: none
}

.faq-list>li:hover .anchor {
    display: inline
}

.faq-list>li {
    border: 1px solid #eee;
    padding: .5em
}

内容的提问来源于stack exchange,提问作者David

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 03:03:10