📜 滚动优化

移动端滚动体验直接影响用户感知,主要涉及平滑滚动、惯性滚动、下拉刷新、滚动穿透等问题。

iOS 惯性滚动(橡皮筋效果)

/* ===== 开启 iOS 平滑惯性滚动 ===== */
.scroll-container {
  overflow-y: auto;
  -webkit-overflow-scrolling: touch; /* iOS 惯性滚动 */
  /* 注意:该属性在 iOS 13+ 已自动支持,旧版需手动添加 */
}

/* 隐藏滚动条但保留滚动功能 */
.scroll-hidden {
  overflow-y: auto;
  scrollbar-width: none;           /* Firefox */
  -ms-overflow-style: none;       /* IE */
}
.scroll-hidden::-webkit-scrollbar {
  display: none;                  /* Chrome / Safari */
}

滚动穿透问题

当弹窗/遮罩层打开时,背景页面仍可滚动。

// ===== 解决滚动穿透 =====

// 方式一:body 固定(最常用)
function preventScrollThrough(isOpen) {
  if (isOpen) {
    const scrollY = window.scrollY;
    document.body.style.position = 'fixed';
    document.body.style.top = `-${scrollY}px`;
    document.body.style.width = '100%';
  } else {
    const scrollY = document.body.style.top;
    document.body.style.position = '';
    document.body.style.top = '';
    document.body.style.width = '';
    window.scrollTo(0, parseInt(scrollY || '0') * -1);
  }
}

// 方式二:弹窗内阻止 touchmove 冒泡
modal.addEventListener('touchmove', (e) => {
  e.stopPropagation(); // 阻止事件冒泡到背景
}, { passive: false });

// 方式三:CSS overscroll-behavior
.modal-scroll {
  overscroll-behavior: contain; /* 滚动边界不传递到父元素 */
}

下拉刷新与上拉加载

// ===== 下拉刷新 & 上拉加载更多 =====
let startY = 0;
let isLoading = false;

// 下拉刷新检测
document.addEventListener('touchstart', (e) => {
  startY = e.touches[0].clientY;
}, { passive: true });

document.addEventListener('touchmove', (e) => {
  if (window.scrollY === 0) {
    const deltaY = e.touches[0].clientY - startY;
    if (deltaY > 60 && !isLoading) {
      console.log('🔄 触发下拉刷新');
      // refreshData();
    }
  }
}, { passive: true });

// 上拉加载更多(滚动到底部检测)
window.addEventListener('scroll', () => {
  const { scrollTop, scrollHeight, clientHeight } = document.documentElement;
  if (scrollTop + clientHeight >= scrollHeight - 100) {
    if (!isLoading) {
      console.log('📄 触发加载更多');
      // loadMore();
    }
  }
}, { passive: true });