滚动吸顶感悟分享

1,430 阅读3分钟

前言

当前项目周期需要泳道图拖拽功能为前提下,对多泳道,多标题进行滚动制定展示功能,本人开始进行研究如果是想滚动多标题吸顶

css粘性布局

1.position:sticky

在兼容此样式的浏览器下,效果极好,推荐指数✨✨✨✨✨
使用css提供的css方法进行滚动吸顶功能,下图是此css效果的兼容性,在ios6+以上有比较好的性能
css粘性布局的几个条件:
  1.元素不会脱离文档流,当元素被黏在页面顶部时,在原来文档流中仍然占据位置,类似relative定位
  2.元素相对其最近可滚动的祖先元素粘性定位,如果其祖先元素都不能滚动,则相对于位置定位
  3.元素最近祖先元素定位设置为visible时候,则元素相对于祖先元素进行sticky定位,若是祖先设置为overflow:hidden,则元素不会sticky定位

移动端粘性布局兼容参考文章: www.cnblogs.com/gopark/p/90…

2.scroll监听单需求

单独的导航栏或者标题栏效果,本文档使用reactHooks写法,实现
useEffect(() => {
    let tit = document.getElementById("nav");
    //占位符的位置,添加占位符让fixed抖动效果减少(本人未复现此功能,还是会有抖动效果)
    const rect = tit.getBoundingClientRect(); //获得页面中导航条相对于浏览器视窗的位置
    let inser = document.createElement("div");
    tit.parentNode.replaceChild(inser, tit);
    inser.appendChild(tit);
    inser.style.height = rect.height + "px";
    let titleTop = tit.offsetTop;

    window.addEventListener("scroll", (e) => {
      const btop =
        document.body.scrollTop || document.documentElement.scrollTop;
      //如果滚动距离大于导航条据顶部的距离
      if (btop > titleTop) {
        //为导航条设置fixed效果,css代码不提供咯
        tit.className = "fix";
      } else {
        //移除fixed
        tit.className = "";
      }
    });
  }, []);

单独滚动制定效果参考网站: www.cnblogs.com/liuyk-code/…

fixed引起的抖动问题修复: blog.csdn.net/zx_001/arti…

3.多标题滚动吸顶实现JS篇

1.方式同单标题实现方式一样
注意事项:因为多标题滚动问题,有fixed布局的标题或者导航栏会脱离文档流,因为我们需要提前记住每一个元素渲染完以后的offsetTop位置便于计算
具体代码如下:
  //首次进入是否需要提前计算元素的位置
  let flag = false;
  //滚动元素数据保存数组
  let offestList = [];
  const handleScroll = (e) => {
    //当前scroll滚动的距离
    const hasScrollTop = e.target.scrollTop;
    //fixed或脱离文档流,给予当前数据宽度,100%不然是整个屏幕宽度(作者左右布局分开了)
    const hasClientWidth = e.target.clientWidth;
    const domList = document.querySelectorAll('.laneBoard_title');
    if (!flag) {
      domList?.forEach((item) => {
        offestList.push({
          offsetTop: item.offsetTop,
          node: item,
        });
      });
      if (offestList.length) {
        flag = true;
      }
    }
    let modifyDom = null;
    offestList.forEach((item, index) => {
      const nodeItem = item;
      //判断是否有下一个titleDom
      const currentNode = item?.offsetTop;
      const nextNode = offestList[index + 1]?.offsetTop || -1;
      if (hasScrollTop > currentNode && hasScrollTop < nextNode + 10) {
        modifyDom = item.node;
      }
      if (hasScrollTop > currentNode && nextNode === -1) {
        modifyDom = item.node;
      }
      //每次滚动需要清空上次滚动的
      if (item?.node?.id !== modifyDom?.id) {
        nodeItem.node.style.position = '';
      }
    });
    if (modifyDom?.style && modifyDom.style.position !== 'fixed') {
      modifyDom.style = `position:fixed;top:180px;width:${hasClientWidth}px`;
    }
  };

  const dom = document.querySelector('.laneBoardIndex');
  dom.addEventListener('scroll', handleScroll);
  return () => {
    dom.removeEventListener('scroll', handleScroll);
  };
  
  另外如果标题宽度不是固定的情况下我们需要监听resize去控制标题宽度的变化
  

结尾

最终本人还是使用了position:sticky 粘性布局,并且在浏览器中判断当前浏览器版本配合 多标题滚动JS去实现了当前功能,防着功能在低配浏览器内部不兼容的问题