React中用JS开发响应式轮播图触发getComputedStyle报错如何解决?
报错原因
- 核心原因是DOM元素查询时机错误:你直接在JS代码顶层执行
document.querySelector('.track')时,React组件还未完成挂载渲染,对应class为track的DOM节点还没有插入到文档中,所以查询结果为null。后续在gestureStart回调中把null传入getComputedStyle方法,就触发了参数类型不匹配的报错。 - 附加潜在问题:你注册的触摸事件名错误,原生触摸事件是
touchstart/touchmove/touchend,不是你写的touchdown/touchup,后续就算DOM问题修复也会导致触摸场景下轮播无法正常工作。 - 未做事件监听清理:组件卸载时如果没有移除绑定在window上的事件,会造成内存泄漏,甚至组件卸载后触发事件时访问已经不存在的DOM节点再次报错。
修复方案
遵循React的DOM操作规范,用useRef绑定目标元素、useEffect管理事件监听的生命周期即可解决问题,修复后的完整代码如下:
import { useRef, useEffect } from 'react'; const Carousel = () => { // 用ref绑定track元素,保证拿到渲染后的真实DOM const trackRef = useRef(null); // 手势过程中的临时变量用useRef存储,避免触发不必要的重渲染 const initialPosition = useRef(null); const moving = useRef(false); const transform = useRef(0); const gestureStart = (e) => { initialPosition.current = e.pageX; moving.current = true; // 加非空判断,边界场景也不会报错 if (!trackRef.current) return; const transformMatrix = window.getComputedStyle(trackRef.current).getPropertyValue('transform'); if (transformMatrix !== "none") { transform.current = parseInt(transformMatrix.split(',')[4].trim()) } } const gestureMove = (e) => { if (moving.current && trackRef.current) { const currentPosition = e.pageX; const diff = currentPosition - initialPosition.current; trackRef.current.style.transform = `translateX(${transform.current + diff}px)` } } const gestureEnd = () => { moving.current = false; } useEffect(() => { // 组件挂载完成后再绑定事件 if(window.PointerEvent){ window.addEventListener('pointerdown', gestureStart); window.addEventListener('pointermove', gestureMove); window.addEventListener('pointerup', gestureEnd); } else { // 修正错误的触摸事件名 window.addEventListener('touchstart', gestureStart); window.addEventListener('touchmove', gestureMove); window.addEventListener('touchend', gestureEnd); window.addEventListener('mousedown', gestureStart); window.addEventListener('mousemove', gestureMove); window.addEventListener('mouseup', gestureEnd); } // 组件卸载时清理事件监听,避免内存泄漏 return () => { if(window.PointerEvent){ window.removeEventListener('pointerdown', gestureStart); window.removeEventListener('pointermove', gestureMove); window.removeEventListener('pointerup', gestureEnd); } else { window.removeEventListener('touchstart', gestureStart); window.removeEventListener('touchmove', gestureMove); window.removeEventListener('touchend', gestureEnd); window.removeEventListener('mousedown', gestureStart); window.removeEventListener('mousemove', gestureMove); window.removeEventListener('mouseup', gestureEnd); } } }, []) return ( <div className="container"> <div className="carousel"> {/* 给track元素绑定ref */} <div ref={trackRef} className="track"> <div className="cards"></div> <div className="cards"></div> <div className="cards"></div> <div className="cards"></div> <div className="cards"></div> <div className="cards"></div> <div className="cards"></div> <div className="cards"></div> <div className="cards"></div> <div className="cards"></div> <div className="cards"></div> <div className="cards"></div> </div> </div> </div> ) } export default Carousel;
内容的提问来源于stack exchange,提问作者Priya Sharma
相关产品推荐
相关产品推荐

