页面抖动问题排查

315 阅读1分钟

VID_20240123_162610.gif

根据火炬图发现频繁调用add和remove

image.png

发现问题代码出现在此处

const scrollChange = (y) => {
// ...
  if (pageWrapEl && paginationEl) {
    let { bottom } = pageWrapEl.getBoundingClientRect();
    if (
      Math.ceil(bottom) <= document.body.clientHeight - copyRightElHeihgt &&
      paginationEl.classList.contains("sticky-bottom")
    ) {
      cancelBottomSticky();
      scrollbarsRef.value.setScrollTop(y.scrollTop + paginationEl.offsetHeight);
    } else if (
      Math.ceil(bottom) - 5 >
      document.body.clientHeight - copyRightElHeihgt
    ) {
      makeBottomSticky();
    }
  }
};

const makeBottomSticky = () => {
  paginationEl.classList.add("sticky-bottom");
  paginationEl.style.width = `${pageWrapEl.getBoundingClientRect().width}px`;
  paginationEl.style.left = `${pageWrapEl.getBoundingClientRect().left}px`;
};
const cancelBottomSticky = () => {
  paginationEl.classList.remove("sticky-bottom");
  paginationEl.style.width = "100%";
  paginationEl.style.left = "0";
};

造成抖动的原因就是频繁的调用scrollChange,而makeBottomStickycancelBottomSticky又会频繁地触发scrollChange,造成了死循环。

image.png

scrollChange的逻辑就是往上滚动的时候,paginationEl的底部如果超过了copyRightElHeihgt那块区域5px,就会触发makeBottomSticky,如果不超过,则触发cancelBottomSticky,这两个回调主要是给paginationEl添加/删除sticky-bottom样式

.sticky-bottom {
    position: fixed;
    bottom: 0px;
    box-sizing: border-box;
    border-top: 1px solid var(--2, #e8e9f8);
    background: rgba(255, 255, 255, 0.8);
    box-shadow: 0px -3px 8px 0px rgb(119 118 152 / 5%);
    backdrop-filter: blur(10px);
    z-index: 100;
    width: -webkit-fill-available;
    padding: 16px 30px !important;
  }

可以看出,sticky-bottom的position属性是fixed,意味着它脱离了文档流

因此就知道了抖动的原因:

当往上滚动的时候,触发了makeBottomStickymakeBottomSticky使paginationEl添加了sticky-bottom样式脱离了文档流,所以整个page.scrollHeight减少了,如果此时page.scrollHeight不足以支撑paginationEl的的底部在copyRightElHeihgt以内5px的话,又会调用cancelBottomSticky删除sticky-bottom,此时paginationEl又回到了文档流,又达成了触发makeBottomSticky的情况。

解决办法:

  1. paginationEl一个占位div,这样即使它脱离文档流,page.scrollHeight也不会发生改变

  2. 取消滚事件,采用Intersection Observer