ReactJS打字测试Web应用实现div自动滚动方案咨询
实现React打字测试应用的自动滚动功能
核心思路
通过监听用户输入文本的变化,获取当前光标所在元素的位置,对比滚动容器的可见区域边界,自动调整容器的滚动位置,确保光标始终处于用户可见范围内。
修改TextDisplay组件
- 添加引用(Ref):使用
useRef获取滚动容器和当前光标元素的DOM引用 - 监听输入变化:使用
useEffect在typedText更新时,计算光标与容器的位置差并调整滚动
修改后的完整代码:
import React, { useRef, useEffect } from 'react' export default function TextDisplay({givenText, typedText}) { const containerRef = useRef(null); const cursorRef = useRef(null); let typedArray = typedText.split(''); let givenArray = givenText.split(''); useEffect(() => { if (!cursorRef.current || !containerRef.current) return; const container = containerRef.current; const cursor = cursorRef.current; const containerRect = container.getBoundingClientRect(); const cursorRect = cursor.getBoundingClientRect(); // 计算光标与容器可见区域的位置偏移量 const bottomOffset = cursorRect.bottom - containerRect.bottom; const topOffset = cursorRect.top - containerRect.top; // 根据偏移量自动调整滚动位置 if (bottomOffset > 0) { container.scrollTop += bottomOffset; } else if (topOffset < 0) { container.scrollTop += topOffset; } }, [typedText]); return ( <div ref={containerRef} className='text-justify w-4/5 sm:w-3/5 text-base sm:text-lg md:text-xl lg:text-2xl h-full overflow-y-auto p-1' > {givenArray.map((val, ind) => { if (val == typedArray[ind] && ind < typedArray.length) { return ( <div ref={ind === typedArray.length - 1 ? cursorRef : null} key={ind} className={`${ind === typedArray.length - 1 ? 'border-r-2' : ''} ${typedArray.length === 0 && ind === 0? 'border-l-2' : ''} character inline border-purple-500 text-purple-700`} > {val} </div> ) } else if(val !== typedArray[ind] && ind < typedArray.length){ return ( <div ref={ind === typedArray.length - 1 ? cursorRef : null} key={ind} className={`${ind === typedArray.length - 1 ? 'border-r-2' : ''} ${typedArray.length === 0 && ind === 0? 'border-l-2' : ''} character inline border-purple-500 ${val===' '?'underline decoration-red-500':'text-red-500'}`} > {val} </div> ) } else { return ( <div ref={typedArray.length === 0 && ind === 0 ? cursorRef : null} key={ind} className={`${ind === typedArray.length - 1 ? 'border-r-2' : ''} ${typedArray.length === 0 && ind === 0? 'border-l-2' : ''} character inline border-purple-500 text-slate-400`} > {val} </div> ) } })} </div> ) }
方案优势
- 无需拆分文本段落,适配任意长度的输入内容
- 基于DOM元素实际位置计算滚动,自动适配不同屏幕尺寸和字体大小
- 同时支持输入前进和退格操作时的滚动调整,全程保证光标可见
内容的提问来源于stack exchange,提问作者Shubham Sharma
相关产品推荐
相关产品推荐

