当前位置 博文首页 > 纸飞机博客:记一次无缝监听元素不可见时吸顶

    纸飞机博客:记一次无缝监听元素不可见时吸顶

    作者:[db:作者] 时间:2021-08-16 16:04

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

    需求:

    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
    下一篇:没有了