前端
一点也不简单

记一次无缝监听元素不可见时吸顶

以代码为主,原理大家都懂,只是要做到平滑切换有些问题

需求:

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查看

赞(1) 打赏
未经允许不得转载:专注前端开发和vps技术交流的博客-纸飞机 » 记一次无缝监听元素不可见时吸顶

评论 2

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址
  1. #1

    Awesome post! Keep up the great work! 🙂

    SEO Company9个月前 (01-22)回复
  2. #2

    Great content! Super high-quality! Keep it up! 🙂

    AffiliateLabz9个月前 (02-16)回复

觉得文章有用就打赏一下文章作者

微信扫一扫打赏