如题:客户提出这样一个奇怪的需求。
自动获取网页内容中的h2标签并添加到侧边栏作为定位,然后点击侧边栏的标题,右边的文章侧定位到对应的位置。
经过多次修改测试后,以下方法非常简单就实现了这个功能。
要是在WP上,不得又是各种插件才能实现。
第一步:
给新闻详情加上class类:例如我给详情添加了new-pages来作为唯一标识。
如:
<div class="content new-pages fs-14 fs-sm-16 lh-2 mb-3" > 新闻详情内容 </div>
然后在侧边栏添加:
<div class="nav "> <div id="outputnav" class="nav-left-menu mb-2"></div> </div>
用于接收输出获取到的H2标题。
然后使用JS如下:
document.addEventListener("DOMContentLoaded", function () {
const content = document.querySelector('.new-pages'); // 固定容器
const tocContainer = document.getElementById('outputnav');
if (!content || !tocContainer) return;
// 递归查找 .new-pages 中的所有 h2(不管嵌套在哪个 div 中)
const headings = content.querySelectorAll('h2');
headings.forEach((heading, index) => {
const anchorId = 'page' + (index + 1);
// 避免重复添加锚点
if (document.getElementById(anchorId)) return;
// 创建锚点偏移
const offsetDiv = document.createElement('div');
offsetDiv.className = 'anchor-offset';
offsetDiv.id = anchorId;
heading.parentNode.insertBefore(offsetDiv, heading); // 插入到 h2 前面
// 创建目录链接
const link = document.createElement('a');
link.href = '#' + anchorId;
link.className = 'toc-link';
link.innerHTML = `
<div class="i"><i class="bi bi-info-circle-fill fs-12"></i></div>
<div class="name">${heading.textContent.trim()}</div>
`;
tocContainer.appendChild(link);
});
});JS的作用就是:
1:递归查找H2标签,并获取到他的标题,存入到:outputnav中,
2:添加A标签,链接为:#page1, #page2,#page3等,同时添加:toc-link
最终形成:
<div class="nav "> <div id="outputnav" class="nav-left-menu mb-2"> <a href="#page1" class="toc-link"><div class="i"><i class="bi bi-info-circle-fill fs-12"></i></div><div class="name">标题1</div></a> <a href="#page2" class="toc-link"><div class="i"><i class="bi bi-info-circle-fill fs-12"></i></div><div class="name">标题2</div></a> <a href="#page3" class="toc-link"><div class="i"><i class="bi bi-info-circle-fill fs-12"></i></div><div class="name">标题3</div></a> </div> </div>
3:给文章中添加偏移锚点:
<div class="anchor-offset" id="pageID号"></div>
最后稍微写一下样式就可以了。
.anchor-offset {
display: block;
position: relative;
top: -80px;
height: 0;
visibility: hidden;
}
.nav-left-menu .toc-link{
display: flex;
margin-bottom: 15px;
font-size: 16px;
}
.nav-left-menu .toc-link .i{
width:20px;
}
.nav-left-menu .toc-link .i i{
transform: scale(1.5);
}
.nav-left-menu .toc-link .name{
width:calc(100% - 20px);
}然后我们需要给左边的导航添加点击高亮和下滑到对应的PAGE时也高亮。
有时候左边点击添加高亮会失效,比如说明明已经点了倒数第二个toc-link,但是还是最后一个是高亮状态
页面加载时: 计算页面每个部分的位置,并生成目录链接。
点击目录项: 平滑滚动到对应部分,并高亮显示当前目录项。
滚动时: 根据当前滚动位置高亮显示对应的目录项。
核心:给点击事件加上独立的 active 状态控制,并临时禁用 scroll 判断。
$(document).ready(function() {
const tocLinks = $('.toc-link');
let pageSections = [];
let isClickScrolling = false;
// 初始化收集 offsetTop
function updatePageSections() {
pageSections = [];
tocLinks.each(function() {
var targetId = $(this).attr('href').substring(1);
var target = $('#' + targetId);
if (target.length) {
pageSections.push({
id: targetId,
top: target.offset().top
});
}
});
}
updatePageSections();
// 监听窗口大小变化重新计算
$(window).on('resize', updatePageSections);
// 点击 toc-link 时处理
tocLinks.on('click', function(e) {
e.preventDefault();
const targetId = $(this).attr('href').substring(1);
const target = $('#' + targetId);
if (target.length) {
isClickScrolling = true;
$('html, body').stop().animate({
scrollTop: target.offset().top - 100
}, 400, function() {
isClickScrolling = false;
});
tocLinks.removeClass('active');
$(this).addClass('active');
}
});
// 滚动监听
$(window).on('scroll', function() {
if (isClickScrolling) return;
const scrollTop = $(window).scrollTop();
let currentId = null;
for (let i = 0; i < pageSections.length; i++) {
if (scrollTop >= pageSections[i].top - 150) {
currentId = pageSections[i].id;
} else {
break;
}
}
if (currentId) {
tocLinks.removeClass('active');
$('.toc-link[href="#' + currentId + '"]').addClass('active');
}
});
});修改后暂时没有发现问题。