React图片滑块滚动函数始终定位同一位置问题排查
React图片滑块切换点点击异常问题
我用React开发图片滑块,切换点数量和图片卡片一致,但滚动函数仅首次点击有效,且无论点击哪个切换点,滑块都会定位到前两张卡片的中间位置(比如点击第四个切换点,仍滚到第一张与第二张中间)。怀疑问题出在magicWallOffsetLeft的计算逻辑或CSS宽度设置上,但无法确定具体原因。
相关代码
Work.js组件
import React, { useEffect, useState } from 'react' import './Work.css' import Cta from '../atoms/Cta' import Headphone from '../assets/images/headphones3.png' import Calendar from '../assets/images/calendar.png' import DevConnector from '../assets/images/dev.png' import Bulls from '../assets/images/bulls2.png' import Expenses from '../assets/images/reactExpenses.png' import SixFlags from '../assets/images/sixflags.png' import useDots from '../hooks/useDots'; const images = [Calendar, Headphone, SixFlags, DevConnector, Bulls, Expenses]; const Work = () => { const [activeIndex, setActiveIndex] = useDots(images.length); const [showDots, setShowDots] = useState(false); useEffect(() => { function handleResize() { setShowDots(window.innerWidth <= 810); } handleResize(); window.addEventListener('resize', handleResize); return () => { window.removeEventListener('resize', handleResize); }; }, []); function handleDotClick(index) { console.log("Clicked dot with index:", index); setActiveIndex(index); const targetCard = document.querySelector(`[data-id="${index}"]`); console.log("Target card:", targetCard); if (targetCard) { const magicWall = document.querySelector('#home-magicwall ul'); const magicWallRect = magicWall.getBoundingClientRect(); const magicWallOffsetLeft = magicWallRect.left + window.scrollX; console.log("Magic wall:", magicWall); console.log("Target card offsetLeft:", targetCard.offsetLeft); console.log("Magic wall offsetLeft:", magicWall.offsetLeft); magicWall.scroll({ left: targetCard.offsetLeft - magicWallOffsetLeft, behavior: 'smooth' }); } } return ( <div className="main-container"> <section id="work"> <div id="header"> <h2>My Work</h2> </div> <div className="text-zone-2"> <div> <p> A small gallery of recent projects chosen by me. I've done them all together with amazing people from companies around the globe. It's only a drop in the ocean compared to the entire list. Interested to see some more? Visit my work page. <br /> </p> </div> <div className="btn-container"> <Cta className="btn" link="https://github.com/mateoghidini1998" content="See More" /> </div> </div> <div className="fake-big-2">Work</div> </section> {showDots && ( <div className="dots"> {images.map((image, index) => ( <button key={index} className={`dot ${index === activeIndex ? 'active' : ''}`} onClick={() => handleDotClick(index)} ></button> ))} </div> )} <div id="home-magicwall" className="fake-magicwall"> <ul> {images.map((image, index) => ( <li key={index} className={`magic-wall_item ${index === activeIndex ? 'active' : ''}`}> <img src={image} alt="image" /> <div className="hover-content"></div> <a href="/" className="colorbox" data-id={index}></a> </li> ))} </ul> </div> </div> ); }; export default Work;
useDots.js自定义钩子
import { useState } from 'react'; function useDots(images) { const [activeIndex, setActiveIndex] = useState(0); return [activeIndex, setActiveIndex]; } export default useDots;
部分CSS代码
.fake-magicwall { background-color: rgba(255, 255, 255, 0.1); position: relative; } .fake-magicwall ul { list-style: none; display: flex; display: -ms-flexbox; display: -webkit-box; flex-wrap: wrap; margin: 0; padding: 0; } .fake-magicwall ul li { width: 50%; height: 550px; position: relative; overflow: hidden; display: list-item; } .fake-magicwall ul li:hover .magic-wall_item { transform: scale(1.14); } .magic-wall_item { position: absolute; top: 0; left: 0; bottom: 0; right: 0; transition: transform 0.5s, opacity 0.5s; } .fake-magicwall img { width: 100%; height: 100%; object-fit: cover; } @media only screen and (max-width: 810px) { .fake-magicwall ul { overflow: hidden; overflow-x: auto; flex-wrap: nowrap; width: 100%; } #home-magicwall { width: 100%; overflow-x: auto; position: relative; } .fake-magicwall ul li { width: 100%; flex-shrink: 0; } .dot { width: 15px; height: 15px; border-radius: 50%; margin: 10px; } }
问题原因及修复方案
1. 目标元素选择错误
你当前通过document.querySelector('[data-id="${index}"]')选中的是<a>标签,但这个标签是绝对定位在<li>内部的,它的offsetLeft是相对于父元素<li>的,而非<ul>,导致滚动位置计算完全错误。应该直接选择对应的<li>元素。
2. 滚动位置计算逻辑错误
scrollLeft是元素自身的滚动距离,不需要考虑元素在页面中的绝对位置,直接使用目标<li>相对于<ul>的offsetLeft即可,之前的magicWallOffsetLeft属于多余计算,反而导致位置偏移。
3. 优化React写法(推荐)
用useRef获取<ul>元素,替代document.querySelector,更符合React组件化规范,避免DOM结构变化引发的选择错误。
修复后的代码修改
Work.js组件修改
import React, { useEffect, useState, useRef } from 'react' // 其他导入保持不变 const Work = () => { const [activeIndex, setActiveIndex] = useDots(images.length); const [showDots, setShowDots] = useState(false); const magicWallRef = useRef(null); // 添加ref引用 // handleResize的useEffect保持不变 function handleDotClick(index) { console.log("Clicked dot with index:", index); setActiveIndex(index); // 直接获取对应的li元素 const targetLi = magicWallRef.current?.children[index]; if (targetLi && magicWallRef.current) { magicWallRef.current.scroll({ left: targetLi.offsetLeft, behavior: 'smooth' }); } } return ( <div className="main-container"> {/* 其他内容保持不变 */} <div id="home-magicwall" className="fake-magicwall"> {/* 给ul添加ref属性 */} <ul ref={magicWallRef}> {images.map((image, index) => ( <li key={index} className={`magic-wall_item ${index === activeIndex ? 'active' : ''}`}> <img src={image} alt="image" /> <div className="hover-content"></div> <a href="/" className="colorbox"></a> {/* 可删除data-id属性 */} </li> ))} </ul> </div> </div> ); }; export default Work;
CSS调整(可选)
确保移动端下<ul>的宽度自适应所有<li>的总宽度,避免滚动异常:
@media only screen and (max-width: 810px) { .fake-magicwall ul { overflow-x: auto; flex-wrap: nowrap; width: fit-content; /* 替换原width:100%,让ul宽度等于所有li的总宽度 */ } /* 其他样式保持不变 */ }
内容的提问来源于stack exchange,提问作者tukitooo1998
相关产品推荐
相关产品推荐

