如何在单页网站中添加自动滚动至下一区块的功能?
实现区块间自动平滑滚动效果
要实现滚动到屏幕一半位置时自动平滑切换到下一/上一区块的效果,可以通过监听滚动事件、判断滚动方向与阈值,结合平滑滚动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
相关产品推荐
相关产品推荐

