You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用GSAP实现可变高度分屏滚动,回滚功能异常求助

分屏滚动向上回滚异常问题排查与修复

问题背景

我使用GSAP的gsap.to实现类FullPage的分屏滚动网站,大部分section默认高度与屏幕一致,但存在部分section(如示例中的section_4)内容高度超过屏幕的情况。目前向下滚动到高内容区域功能正常,但向上回滚时出现异常,无法正常切换到上一个section。

核心修复代码

const sections = $("section");
const sectionContents = $("section > div");

let currentSectionIndex = 0;
let isScrolling = false;
let isTouching = false;

$(document).on("wheel", handleWheel);
$(document).on("touchstart", handleTouchStart);
$(document).on("touchmove", handleTouchMove);
$(document).on("touchend", handleTouchEnd);

let touchStartY = 0;
let touchStartTime = 0;

function handleTouchStart(event) {
  console.log('handleTouchStart - is on');
  isTouching = true;
  touchStartY = event.originalEvent.touches[0].clientY;
  touchStartTime = Date.now();
}

function handleTouchMove(event) {
  console.log('handleTouchMove - is on');
  if (!isTouching) return;
  event.preventDefault();
}

function handleTouchEnd(event) {
  console.log('handleTouchEnd - is on');
  isTouching = false;
  const touchEndY = event.originalEvent.changedTouches[0].clientY;
  const touchEndTime = Date.now();

  const deltaY = touchEndY - touchStartY;
  const deltaTime = touchEndTime - touchStartTime;
  const velocity = Math.abs(deltaY / deltaTime);
  const direction = deltaY > 0 ? "down" : "up"; // 新增触摸方向判断

  const currentSection = sections.eq(currentSectionIndex);
  const contentHeight = currentSection.find("> div").prop("scrollHeight");
  const windowHeight = $(window).height();

  if (contentHeight > windowHeight) {
    scrollInSection(currentSection, deltaY, direction); // 传入方向参数
  } else {
    if (velocity > 1) {
      scrollInSection(currentSection, deltaY, direction);
    } else {
      scrollToSection(currentSection);
    }
  }
}

function handleWheel(event) {
  event.preventDefault();

  if (isScrolling) return;
  isScrolling = true;

  const deltaY = event.originalEvent.deltaY;
  const direction = deltaY > 0 ? "down" : "up";

  const targetSection = sections.eq(currentSectionIndex);

  if (targetSection.hasClass("large-content")) {
    scrollInSection(targetSection ,deltaY, direction);
  } else {
    if (direction === "down") {
      currentSectionIndex = Math.min(currentSectionIndex + 1, sections.length - 1);
    } else {
      currentSectionIndex = Math.max(currentSectionIndex - 1, 0);
    }

    scrollToSection(sections.eq(currentSectionIndex));
  }
}

function scrollInSection(targetSection, deltaY, direction) {
  console.log('scrollInSection - to ' + targetSection.attr('class'));
  const windowHeight = $(window).height();
  const sectionContent = targetSection.find("> div");
  const currentScrollTop = sectionContent.scrollTop();
  const sectionHeight = sectionContent.prop("scrollHeight");
  const sectionVisibleHeight = windowHeight / 3; 
  let targetScrollTop;

  const isAtTop = currentScrollTop === 0;
  const isAtBottom = currentScrollTop + windowHeight === sectionHeight;

  // 修复:边界滚动时切换对应section
  if (isAtTop && deltaY < 0 && direction === "up") {
    currentSectionIndex = Math.max(currentSectionIndex - 1, 0);
    scrollToSection(sections.eq(currentSectionIndex));
    return;
  }
  if (isAtBottom && deltaY > 0 && direction === "down") {
    currentSectionIndex = Math.min(currentSectionIndex + 1, sections.length - 1);
    scrollToSection(sections.eq(currentSectionIndex));
    return;
  }

  if (deltaY > 0) {
    targetScrollTop = Math.min(currentScrollTop + sectionVisibleHeight, sectionHeight - windowHeight);
  } else {
    targetScrollTop = Math.max(currentScrollTop - sectionVisibleHeight, 0);
  }

  // 统一用GSAP实现内容滚动,保持动画逻辑一致
  gsap.to(sectionContent, {
    scrollTop: targetScrollTop,
    duration: 0.5,
    onComplete: () => {
      isScrolling = false;
    }
  });
}

function scrollToSection(targetSection) {
  console.log('scrollToSection to ' + targetSection.attr('class'), targetSection.height(), $(window).height());
  const targetY = targetSection.offset().top;

  gsap.to(window, {
    duration: 1.7,
    scrollTo: {
      y: targetY
    },
    onComplete: function() {
      isScrolling = false;
    }
  });
}

错误分析与修复说明

  1. 缺失边界滚动的section切换逻辑
    原代码中,当高内容section滚到顶部且向上滚动时,仅重置isScrolling后返回,未执行切换到上一个section的操作,导致无法向上回滚。修复时在对应条件分支中更新currentSectionIndex并调用scrollToSection完成切换。

  2. 触摸事件未传递方向参数
    handleTouchEnd中调用scrollInSection时未传入direction参数,导致触摸操作下的边界滚动判断失效。新增方向计算并传入参数即可解决该问题。

  3. 动画库混用优化(可选)
    原代码同时使用jQuery的animate和GSAP动画,统一为GSAP实现内容区域滚动,可保持动画逻辑一致并利用GSAP的性能优势。

内容的提问来源于stack exchange,提问作者Jc Denton

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 21:34:58