滚动时切换页面背景色的Vanilla JS实现求助
Fixing & Optimizing Your Vanilla JS Scroll-Based Background Switcher
Hey there! Let's break down what's going wrong with your current code and build a working, efficient version of your scroll-triggered background color changer.
First, Let's Diagnose the Issues in Your Original Code
- Broken Class Storage: When you run
let cyan = bdy.classList.add('lightCyan');,classList.add()returnsundefined—so yourcolorsarray ends up filled with nothing butundefinedvalues. That's why the loop in your scroll event does nothing useful. - Incorrect Scroll Condition: Your condition
document.documentElement.scrollTop || document.body.scrollTop > window.innerHeightis logically flawed. The||operator here doesn't group the scrollTop values together properly, so it's only checking ifdocument.body.scrollTopis greater than the viewport height. - Wrong Class Switching Logic: The loop where you push
iintocolorsdoesn't actually toggle or switch any classes on the body—it just adds numbers to an array, which doesn't affect the DOM at all.
Working Fixed Code
Let's rewrite the JavaScript to properly handle scroll positions and class switching, plus tweak the CSS for better layout.
HTML (No Changes Needed)
<html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <link rel="css\style.css"> <title>Site experiment</title> </head> <body> <section> <h1 id="first-h1">This site is an experiment on scroll effects</h1> </section> <section> <h1 id="second-h1">I really hope this helps me learn vanilla JavaScript better</h1> </section> <section> <h1 id="third-h1">I think it will honestly</h1> </section> <section> <h1 id="fourth-h1">Or maybe it will frustrate me till the end of time</h1> </section> <section> <h1 id="fifth-h1">Even if that does happen, I'll still keep trying</h1> </section> </body> <script src="js\app.js"></script> </html>
CSS (Tweaked for Better Centering)
@import url('https://fonts.googleapis.com/css?family=Roboto+Mono'); * { margin: 0; padding: 0; box-sizing: border-box; font-family: 'Roboto Mono', monospace; } body { background-color: #E5E1EE; transition: background-color 0.3s ease; /* More specific transition */ } section { height: 100vh; display: flex; /* Center heading vertically/horizontally */ align-items: center; justify-content: center; padding: 2rem; } h1 { text-align: center; max-width: 80%; } .lightCyan { background-color: #DFFDFF; } .darkSkyBlue { background-color: #90BEDE; } .aquamarine { background-color: #68EDC6; } .electricBlue { background-color: #90F3FF; }
JavaScript (Fixed & Functional)
const body = document.querySelector('body'); const sections = document.querySelectorAll('section'); // Map each section to its corresponding background class const sectionColorMap = [ '', // First section uses default body color 'lightCyan', 'darkSkyBlue', 'aquamarine', 'electricBlue' ]; function handleScroll() { // Get current scroll position (cross-browser support) const scrollPos = window.scrollY || document.documentElement.scrollTop; const viewportHeight = window.innerHeight; // Loop through sections to find which one is currently in view sections.forEach((section, index) => { const sectionTop = section.offsetTop; // Trigger when we've scrolled to the middle of the section if (scrollPos >= sectionTop - viewportHeight / 2) { // Remove all existing color classes first body.classList.remove('lightCyan', 'darkSkyBlue', 'aquamarine', 'electricBlue'); // Add the corresponding color class for this section if (sectionColorMap[index]) { body.classList.add(sectionColorMap[index]); } } }); } // Add scroll event listener window.addEventListener('scroll', handleScroll); // Run once on page load to set initial state handleScroll();
Optimization Tips for Better Performance
- Throttle the Scroll Event: Scroll events fire hundreds of times per second, which can cause jank. Add a throttle function to limit how often
handleScrollruns:function throttle(func, delay = 100) { let lastCall = 0; return (...args) => { const now = Date.now(); if (now - lastCall >= delay) { func(...args); lastCall = now; } }; } // Use throttled version in event listener window.addEventListener('scroll', throttle(handleScroll)); - Use Intersection Observer API: For even better performance (especially on mobile), replace the scroll listener with an Intersection Observer. This API is designed to detect when elements enter/exit the viewport without listening to scroll events:
const observerOptions = { root: null, // Use viewport as root rootMargin: '-50% 0px -50% 0px', // Trigger when section is centered in viewport threshold: 0 }; const observer = new IntersectionObserver((entries) => { entries.forEach(entry => { if (entry.isIntersecting) { const sectionIndex = Array.from(sections).indexOf(entry.target); body.classList.remove('lightCyan', 'darkSkyBlue', 'aquamarine', 'electricBlue'); if (sectionColorMap[sectionIndex]) { body.classList.add(sectionColorMap[sectionIndex]); } } }); }, observerOptions); // Observe each section sections.forEach(section => observer.observe(section)); - Preselect Elements: We already do this with
const sections = document.querySelectorAll('section')—avoid querying the DOM inside scroll/observer callbacks, as DOM queries are expensive.
内容的提问来源于stack exchange,提问作者eddiepearson
相关产品推荐
相关产品推荐

