本文详解如何利用JavaScript实现多个导航标题的吸顶效果。通过监听window滚动事件,结合offsetTop计算每个标题的可视范围,并处理最后一个标题的特殊边界情况,确保在PC端和移动端滑动时,当前区域标题能正确固定于顶部,提升用户体验。
多标题吸顶需求分析
针对导航栏的吸顶功能,PC端与移动端的需求存在差异。PC端通常只需单个顶部导航固定,而移动端在页面滑动时,往往需要实现多个标题的依次吸顶,例如地区选择列表中省份标题的固定显示。
单个标题吸顶与多个标题吸顶的核心区别在于作用域的控制。多标题吸顶需划定一个高度区间,在该区间内仅允许一个标题处于吸顶状态,其余标题保持固定定位或其他样式。
页面布局与样式设置
一、页面布局及样式
为测试效果,此处使用了多个重复的section标签。实际开发中,请根据具体需求调整布局结构和CSS样式。
<body>
<ul id="container">
<h1>实现多个标题的吸顶</h1>
<section>
<div class="box">header1</div>
<li>1</li>
<li>1</li>
<li>1</li>
<li>1</li>
<li>1</li>
<li>1</li>
</section>
<!--设置多个如header1的子列表,窗口可以进行滚动,此处省略-->
<section>
<div class="box">header5</div>
<li>1</li>
<li>1</li>
<li>1</li>
<li>1</li>
<li>1</li>
<li>1</li>
</section>
</ul>
</body>
<style type="text/css">
* {
padding: 0;
margin: 0;
}
ul {
width: 100%;
}
li {
width: 200px;
color: white;
margin: 10px;
list-style: none;
border-radius: 5px;
border: 1px solid #191970;
background: #4169E1;
text-align: center;
}
div {
width: 100%;
height: 30px;
color: white;
padding-left: 20px;
background: #DC143C;
}
.box1 {
position: fixed;
top: 0;
}
</style>
JavaScript核心逻辑实现
二、JS的编写
第一步,获取所有需要执行吸顶操作的标题元素。建议这些标题使用统一的布局和样式,以便更高效、统一地获取和处理。
var box = document.getElementsByClassName('box'), //获取所有需要吸顶效果的标题
section = document.getElementsByTagName('section'); //获取所有子列表,后面有用
第二步,统计标题数量并定义一个数组,用于存储每个标题距离父元素的垂直偏移量(offsetTop)。
var ot = [], //存储每个标题的offsetTop
len = box.length; //标题的个数
第三步,遍历所有标题元素,计算并获取其offsetTop值,将这些值存入上述数组中。
for(let i=0; i<len; i++) {
ot.push(box[i].offsetTop); //获取每个标题的offsetTop
}
第四步,监听window的滚动事件,获取当前滚动高度scrollTop。若滚动高度位于第i个标题的offsetTop与第i+1个标题的offsetTop之间(例如滚动高度处于header1和header2的offsetTop之间,此时header1吸顶),则为第i个标题添加box1样式,从而实现吸顶效果。
window.onscroll = function () {
//获取滚动的高度
var st = document.documentElement.scrollTop || document.body.scrollTop;
for(let i=0; i<len; i++) {
if(st>ot[i] && st<ot[i+1]) { //滚动时监听位置,为标题的吸顶设置一个现实范围
box[i].className = 'box box1';
} else {
box[i].className = 'box';
}
}
}
第五步,上述逻辑存在一个潜在问题:当滚动至最后一个标题(即索引为i)时,无法获取第i+1个标题的offsetTop值,导致判断逻辑失效。
解决方案:从第一步获取的section标签集合中取出最后一个子列表(section[0]),计算该子列表的高度,进而推算出最后一个标题的有效显示高度范围,并将此范围值存入ot数组中,以完善边界判断。
//获取最后一个子列表的高度,为了设置最后一个吸顶标题的位置
//section[len-1].getBoundingClientRect().height
//此方法返回一个number
ot.push(box[len-1].offsetTop + section[len-1].getBoundingClientRect().height);
效果展示与完整代码
三、最后效果


完整js代码
var box = document.getElementsByClassName('box'), //获取所有需要吸顶效果的标题
section = document.getElementsByTagName('section'); //获取所有子列表
var ot = [], //存储每个标题的offsetTop
len = box.length; //标题的个数
for(let i=0; i<len; i++) {
ot.push(box[i].offsetTop); //获取每个标题的offsetTop
}
//获取最后一个子列表的高度,为了设置最后一个吸顶标题的位置
//section[len-1].getBoundingClientRect().height
//此方法返回一个number
ot.push(box[len-1].offsetTop + section[len-1].getBoundingClientRect().height);
window.onscroll = function () {
//获取滚动的高度
var st = document.documentElement.scrollTop || document.body.scrollTop;
for(let i=0; i<len; i++) {
if(st>ot[i] && st<ot[i+1]) { //滚动时监听位置,为标题的吸顶设置一个现实范围
box[i].className = 'box box1';
} else {
box[i].className = 'box';
}
}
}
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持本站。