当前位置 博文首页 > 纸飞机博客:记一次无缝监听元素不可见时吸顶
以代码为主,原理大家都懂,只是要做到平滑切换有些问题
tab栏要在它被滚动到顶部时吸顶。
会抖动,不流畅
分析了一下,实际上当元素吸顶后原来区域的元素占据的位置是空了的,那么也就会有一个下面的元素向上占位的过程,解决方法是填充该区域
代码:
// 获取当前滚动条高度
export const getScrollTop = function (params) {
let scrollTop = 0;
if (document.documentElement && document.documentElement.scrollTop) {
scrollTop = document.documentElement.scrollTop;
} else if (document.body) {
scrollTop = document.body.scrollTop;
}
return scrollTop;
}
这是一个导出的方法,需要后面引入
tab页面代码:
tab的html
<template>
<div class="match-tab" id="match-tab" :class="{'fixed': tabFixed}" :style="{'top': page.appNavigationHeight + 'px'}">
<!-- <div class="item" @click="sendChildData(0)">
<span :class="selectIndex == 0 ? 'active' : ''">实况</span>
</div> -->
<div class="item" @click="sendChildData(2)">
<span :class="selectIndex == 2 ? 'active' : ''">图片墙</span>
</div>
<div class="item" @click="sendChildData(1)" >
<span :class="selectIndex == 1 ? 'active' : ''">时间轴</span>
</div>
<div class="item" @click="sendChildData(3)">
<span :class="selectIndex == 3 ? 'active' : ''">热门</span>
</div>
</div>
</template>
style
<style lang="less" scoped>
.match-tab{
margin-top: 5px;
display: flex;
justify-content: space-between;
width: 100%;
background: rgba(255,255,255,.3);
&.fixed {
position: fixed;
z-index: 1;
top: 0px;
left: 0px;
margin-top: 0;
// padding-bottom: 10px;
background: rgba(255,255,255,.9);
}
.item{
width: 50%;
display: flex;
height: 45px;
align-items: center;
justify-content: center;
color: #333;
font-size: 15px;
span{
display: inline-block;
height: 100%;
line-height: 45px;
box-sizing: border-box;
&.active{
border-bottom: 3px solid #49a4f3;
color: #49a4f3;
}
}
}
}
</style>
script引入方法
import { getScrollTop } from "@/libs/utils";
tab的几个需要的data
props:['selectIndex'],
data(){
return{
// selectIndex:this.$parent.tabSelect
page: this.$parent.page,
tabFixed: false,
}
},
props里的和page无需理会,这是切换tab用的
methods
onScroll(options) {
const el = document.querySelector(options.el);
if (!el) return;
let isLower = false;
let diffValue = 0;
let elTop = 0;
let elHeight = options.isFixed === true ? el.offsetHeight : 0;
if (typeof options.diffValue === "function") {
diffValue = options.diffValue(el) || 0;
}
// 开始监听滚动条
window.addEventListener("scroll", () => {
let scrollTop = getScrollTop();
if (typeof options.onScroll === "function") {
options.onScroll(el, scrollTop);
}
if (isLower === false) {
// 元素顶端到可见区域(网页)顶端的距离
let eleClientTop = el.getBoundingClientRect().top;
// 网页指定元素触碰顶部时
if (eleClientTop <= diffValue) {
elTop = el.offsetTop + elHeight;
isLower = true;
if (typeof options.onLower === "function") {
options.onLower(el);
}
}
} else if (isLower === true) {
if (scrollTop + elHeight < elTop) {
elTop = 0;
isLower = false;
if (typeof options.onHigher === "function") {
options.onHigher(el);
}
}
}
});
},
// 监听元素位置
tabsListener() {
let versionCode = this.page.versionCode;
let isInApp = this.page.isInApp;
if (isInApp && versionCode < 66) {
return;
}
let tabsEl = document.querySelector("#match-tab");
if (!tabsEl) {
return;
}
//添加占位元素
function addPlaceholderEl(el) {
let height = el.offsetHeight;
console.log(height)
let placeholderEl = window.document.createElement("div");
placeholderEl.style.height = height + "px";
placeholderEl.style.width = "100%";
el.parentNode.insertBefore(placeholderEl, el.nextSibling);
return placeholderEl;
}
let tabsHeight = tabsEl.offsetHeight + this.page.appNavigationHeight;
//监听tab栏
this.onScroll({
el: "#match-tab",
isFixed: true,
diffValue: el => {
return this.page.appNavigationHeight; //this.page.isInMiniprogram ? 0 : el.offsetHeight;
},
onLower: el => {
this.placeholderEl = addPlaceholderEl(el);
this.tabFixed = true;
},
onHigher: el => {
this.placeholderEl.parentNode.removeChild(this.placeholderEl);
this.tabFixed = false;
}
});
}
mounted
setTimeout(this.tabsListener);
至此,已经可以平滑过渡了,需要看效果的可以微信打开http://m.huaxiyou.cc/app/cloudalbum/1000/detail/58查看
cs