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

如何在单页网站中添加自动滚动至下一区块的功能?

实现区块间自动平滑滚动效果

要实现滚动到屏幕一半位置时自动平滑切换到下一/上一区块的效果,可以通过监听滚动事件、判断滚动方向与阈值,结合平滑滚动API来实现。以下是适配你现有代码的完整实现方案:

完整修改代码

'use client'

import Image from 'next/image'
import { useEffect, useRef } from 'react'

import About from './components/About'
import Lodge from './components/Lodge'
import AboutS from './components/AboutS'
import Reviews from './components/Reviews'
import Blog_h from './components/Blog_h'
import Contacts from './components/Contacts'

export default function Home() {
  // 存储所有section元素
  const sectionsRef = useRef<HTMLElement[]>([])
  // 滚动锁定标记,避免自动滚动时触发重复事件
  const isScrolling = useRef(false)
  // 上一次滚动位置,用于判断滚动方向
  const lastScrollY = useRef(0)

  useEffect(() => {
    // 初始化获取所有section节点
    const sections = Array.from(document.querySelectorAll('section')) as HTMLElement[]
    sectionsRef.current = sections

    // 防抖函数,避免滚动事件频繁触发
    const debounce = (func: () => void, delay: number) => {
      let timeoutId: NodeJS.Timeout
      return () => {
        clearTimeout(timeoutId)
        timeoutId = setTimeout(func, delay)
      }
    }

    const handleScroll = () => {
      if (isScrolling.current) return

      const currentScrollY = window.scrollY
      const windowHeight = window.innerHeight
      const scrollThreshold = windowHeight / 2
      const direction = currentScrollY > lastScrollY.current ? 'down' : 'up'
      lastScrollY.current = currentScrollY

      // 找到当前处于触发阈值范围内的区块索引
      const currentIndex = sectionsRef.current.findIndex(section => {
        const sectionTop = section.offsetTop
        const sectionBottom = sectionTop + section.offsetHeight
        return currentScrollY >= sectionTop - scrollThreshold && currentScrollY < sectionBottom - scrollThreshold
      })

      let targetIndex = currentIndex
      if (direction === 'down' && currentIndex < sectionsRef.current.length - 1) {
        targetIndex = currentIndex + 1
      } else if (direction === 'up' && currentIndex > 0) {
        targetIndex = currentIndex - 1
      } else {
        return // 已经是第一个/最后一个区块,不处理
      }

      // 锁定滚动,开始平滑滚动
      isScrolling.current = true
      window.scrollTo({
        top: sectionsRef.current[targetIndex].offsetTop,
        behavior: 'smooth'
      })

      // 滚动结束后解锁,适配平滑滚动默认时长
      setTimeout(() => {
        isScrolling.current = false
      }, 800)
    }

    // 添加滚动事件监听,使用防抖优化
    const debouncedHandleScroll = debounce(handleScroll, 100)
    window.addEventListener('scroll', debouncedHandleScroll)

    // 清理事件监听
    return () => {
      window.removeEventListener('scroll', debouncedHandleScroll)
    }
  }, [])

  return (
    <div className="">
      <section
        id="home"
        className="bg-local bg-no-repeat bg-center bg-cover bg-test-bg w-full h-[1080px]"
      >
        <div className="font-medium lg:text-[36px] md:text-[28px] sm:text-[24px] leading-normal text-white pt-[619px] pl-[80px]">
          Enjoy your time in Lux in the clouds
        </div>

        <Image className="pt-[30px] pl-[80px]"
          src="/images/portal360.svg"
          alt="Portal 360"
          width={1154}
          height={162}
        />
      </section>

      <section id="about">
        <About />
      </section>

      <section id="lodge">
        <Lodge />
      </section>

      <section id="abouts">
        <AboutS />
      </section>

      <section id="reviews">
        <Reviews />
      </section>

      <section id="ourblog">
        <Blog_h />
      </section>

      <section id="contacts">
        <Contacts />
      </section>
      
    </div>
  )
}

关键实现要点

  • 滚动锁定:通过isScrolling标记避免自动滚动过程中重复触发事件,防止滚动冲突。
  • 方向判断:对比当前滚动位置与上一次位置,确定是向上还是向下滚动。
  • 阈值触发:以屏幕高度的一半作为触发切换的阈值,当滚动距离超过该值时触发自动滚动。
  • 防抖优化:对滚动事件添加防抖处理,减少性能消耗。
  • 平滑滚动:使用window.scrollTo的smooth行为实现自然的过渡效果。

额外建议

确保每个<section>的高度至少为100vh(或与第一个区块高度一致),这样区块切换的视觉体验会更统一。如果你的子组件(如About、Lodge等)已经设置了高度,可忽略此建议。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 18:23:14