实现原理
当元素滑动到一个容器阈值时将其定位变为fixed。由于我的项目要适配很多浏览器,因此用代码实现了,css的sticky暂时不适用,大家可以根据项目来调整
效果
直接上代码
html
<div id="sticky-container">
<div id="sticky-box">
<div id="sticky-top">
<div class="">
xxx
</div>
<div class="">
xxx
</div>
<div class="">
xxx
</div>
</div>
</div>
</div>
javascript
// this.$nextTick是vue的方法,如果是原生代码可以去除掉,这里展示的vue内的写法
{
mounted() {
this.$nextTick(() => {
this.stickyLayout()
window.onresize = () => {
this.stickyLayout()
}
})
},
destroyed() {
document.removeEventListener("scroll", this.scrollHandler);
},
methods: {
// 实现粘性布局
stickyLayout() {
let scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
// 获取要粘性布局的父容器
let stickyContainer = document.getElementById("sticky-container");
// 初始化吸顶距离
let stickyDis = stickyContainer.getBoundingClientRect().top + scrollTop;
// 粘性布局后这个容器position:fixed
let stickyTop = document.getElementById("sticky-top");
let stickyHeight = stickyTop.clientHeight
// 初始化top的值
let topDir = stickyTop.offsetTop
//一般这个footer大家看情况来加上可以去掉,我这个处理是为了让容器不能碰到最下面的元素
let footer = document.getElementById('footer')
let footerTop = footer.offsetTop
// end
if(scrollTop < stickyDis) {
// stickyTop该容器的position改为fixed
stickyTop.style = ""
}
else {
stickyTop.style.position = "fixed";
// 大家根据实际情况来,一般用来避免这个容器超出显示
if(scrollTop + stickyHeight + topDir > footerTop) {
console.log("超过了底部容器")
// 超过了这个容器
stickyTop.style.top = footerTop - (scrollTop + stickyHeight + topDir) + 'px'
}
else {
stickyTop.style.top = topDir + 'px'
}
}
document.removeEventListener("scroll", this.scrollHandler);
document.addEventListener("scroll", this.scrollHandler);
},
scrollHandler() {
let top = document.body.scrollTop || document.documentElement.scrollTop;
// 获取要粘性布局的父容器
let stickyContainer = document.getElementById("sticky-container");
// 初始化吸顶距离
let stickyDis = stickyContainer.getBoundingClientRect().top + top;
// 粘性布局后这个容器position:fixed
let stickyTop = document.getElementById("sticky-top");
let stickyHeight = stickyTop.clientHeight
// 初始化top的值
let topDir = stickyTop.offsetTop
let footer = document.getElementById('footer')
let footerTop = footer.offsetTop
// 如果超过了这个距离
if(top < stickyDis) {
// stickyTop该容器的position改为fixed
stickyTop.style = ""
}
else {
stickyTop.style.position = "fixed";
if(top + stickyHeight + topDir > footerTop) {
// 超过了这个容器
stickyTop.style.top = footerTop - (top + stickyHeight + topDir) + 'px'
}
else {
stickyTop.style.top = topDir + 'px'
}
}
},
}
}
css
/* 并非完整样式,但主要的样式是这样的 */
#sticky-container {
display: flex;
flex-direction: row;
position: relative;
width: 1200px;
}
#sticky-box {
flex: 1;
background-color: white;
padding: 149px 0;
display: flex;
flex-direction: column;
align-items: center;
min-width: 400px;
}
#sticky-top {
display: flex;
flex-direction: column;
align-items: center;
}