页面内的tab导航需要在滚动到视口顶部的时候进行吸顶,这个功能算是比较常见,也比较容易实现。刚开始按照自己想到的最简单的方法来实现,写完代码后进行测试,发现页面有很明显的bug,心里直呼大意了,特此记录下。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<style>
.page-container {
width: 1200px;
margin: 0 auto;
}
.top-area {
height: 300px;
background-color: lightskyblue;
margin-bottom: 20px;
}
.tab {
padding: 0 20px;
display: flex;
justify-content: space-between;
background-color: #f4f4f4;
}
.tab.fixed {
position: fixed;
width: 1200px;
box-sizing: border-box;
top: 0;
}
.tab > div {
padding: 10px 20px;
}
.waterfall {
display: flex;
justify-content: space-between;
flex-wrap: wrap;
align-content: center;
}
.waterfall > div {
margin-top: 20px;
width: 220px;
height: 300px;
background-color: darkseagreen;
margin-bottom: 12px;
}
</style>
</head>
<body>
<div class="page-container">
<div class="top-area">huge element</div>
<div class="tab">
<div class="tab1">tab1</div>
<div class="tab2">tab2</div>
<div class="tab3">tab3</div>
<div class="tab4">tab4</div>
<div class="tab5">tab5</div>
<div class="tab6">tab6</div>
<div class="tab7">tab7</div>
<div class="tab8">tab8</div>
<div class="tab9">tab9</div>
<div class="tab10">tab10</div>
</div>
<div class="tab-holder"></div>
<div class="waterfall">
<div class="item1">item1</div>
<div class="item2">item2</div>
<div class="item3">item3</div>
<div class="item4">item4</div>
<div class="item5">item5</div>
<div class="item6">item6</div>
<div class="item7">item7</div>
<div class="item8">item8</div>
<div class="item9">item9</div>
<div class="item10">item10</div>
<div class="item11">item11</div>
<div class="item12">item12</div>
<div class="item13">item13</div>
<div class="item14">item14</div>
<div class="item15">item15</div>
<div class="item16">item16</div>
<div class="item17">item17</div>
<div class="item18">item18</div>
<div class="item19">item19</div>
<div class="item20">item20</div>
<div class="item21">item21</div>
<div class="item22">item22</div>
<div class="item23">item23</div>
<div class="item24">item24</div>
<div class="item25">item25</div>
<div class="item26">item26</div>
<div class="item27">item27</div>
<div class="item28">item28</div>
<div class="item29">item29</div>
<div class="item30">item30</div>
<div class="item31">item31</div>
<div class="item32">item32</div>
<div class="item33">item33</div>
<div class="item34">item34</div>
<div class="item35">item35</div>
<div class="item36">item36</div>
<div class="item37">item37</div>
<div class="item38">item38</div>
<div class="item39">item39</div>
<div class="item40">item40</div>
<div class="item41">item41</div>
<div class="item42">item42</div>
<div class="item43">item43</div>
<div class="item44">item44</div>
<div class="item45">item45</div>
<div class="item46">item46</div>
<div class="item47">item47</div>
<div class="item48">item48</div>
<div class="item49">item49</div>
<div class="item50">item50</div>
</div>
</div>
</body>
<script>
const tabElem = document.querySelector(".tab");
const tabHolder = document.querySelector(".tab-holder");
const handleScroll = () => {
const { top, height } = tabElem.getBoundingClientRect();
console.log("top", top);
if (top < 0) {
tabElem.classList.add("fixed");
tabHolder.style.height = height + "px";
} else {
tabElem.classList.remove("fixed");
tabHolder.style.height = 0;
}
};
document.addEventListener("scroll", handleScroll);
</script>
</html>
上面的代码在打开页面后,向上滚动过程中会发现tab导航一直在闪烁,原因就是tab元素在转变成固定定位的过程,浏览器需要重新计算页面布局和重绘元素,在此期间滚动事件执行了很多遍,导致获取到的top值会出现两极跳转现象,元素会固定定位和原来的定位之间来回切换。
上面的代码由于tab导航元素的定位会发生变化,导致在滚动过程中获取到的top值有问题,之前我们是使用需要定位的上边界来进行判断,那么我们可以选取相邻元素的上下边界是否达到条件来作为tab导航是否应该转为固定定位的依据。
const topAreaElem = document.querySelector(".top-area");
const tabElem = document.querySelector(".tab");
const tabHolder = document.querySelector(".tab-holder");
const handleScroll = () => {
const { bottom } = topAreaElem.getBoundingClientRect();
const { height } = tabElem.getBoundingClientRect();
// 这个20是tab导航与上面相邻元素之间的margin
if (bottom + 20 < 0) {
tabElem.classList.add("fixed");
tabHolder.style.height = height + "px";
} else {
tabElem.classList.remove("fixed");
tabHolder.style.height = 0;
}
};
document.addEventListener("scroll", handleScroll);
完美解决,收官。