以代码为主,原理大家都懂,只是要做到平滑切换有些问题
需求:
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查看