React集成Prismjs后光标移动不重置闪烁周期导致显示延迟问题
问题排查结论
handleKeyDown不是问题根源:该函数仅处理Tab按键逻辑,方向键触发时不会进入自定义分支,也不会阻止默认行为,和光标异常无关联。- 问题根源和pre标签块的渲染逻辑直接相关:你采用的是textarea透明覆盖在高亮pre上层的轻量代码编辑器实现方案,你当前调用的
Prism.highlightAll()会全局扫描页面所有code标签,全量替换内部DOM结构,频繁的重绘操作干扰了同层级textarea的光标闪烁重置逻辑,导致方向键移动光标时没有重置闪烁周期,出现要等光标亮起才能确认位置的问题。
可行解决方案
方案1:优化Prism高亮逻辑,缩小重绘范围
不要使用全局的Prism.highlightAll(),改为仅高亮当前代码块,减少不必要的DOM操作:
import { useState, useEffect, useRef } from "react"; import Prism from "prismjs"; export default function EditCode() { const [content, setContent] = useState(""); // 绑定目标code节点 const codeRef = useRef(null); const handleKeyDown = (e) => { // 原有Tab逻辑保持不变 let value = content, selStartPos = e.currentTarget.selectionStart; if (e.key === "Tab") { value = value.substring(0, selStartPos) + " " + value.substring(selStartPos, value.length); e.currentTarget.selectionStart = selStartPos + 3; e.currentTarget.selectionEnd = selStartPos + 4; e.preventDefault(); setContent(value); } }; // 删掉原来的两个highlightAll useEffect,替换为以下逻辑 useEffect(() => { if (codeRef.current) { // 仅高亮当前code节点,不全局扫描 Prism.highlightElement(codeRef.current); } }, [content]); return ( <section className="codeGlobalContainer" style={{position: 'relative'}}> <textarea className="codeInput" spellCheck="false" wrap="off" cols="200" value={content} onChange={(e) => setContent(e.target.value)} onKeyDown={(e) => handleKeyDown(e)} style={{ position: 'relative', zIndex: 1, color: 'transparent', caretColor: '#000' }} /> <pre className="codeOutput"> {/* 绑定ref到code标签 */} <code ref={codeRef} className={`language-javascript`}>{content}</code> </pre> </section> ); }
方案2:调整层级避免交互干扰
给pre/code块添加pointer-events: none和更低的层级,完全避免下层节点干扰textarea的交互响应,CSS参考如下:
.codeGlobalContainer { position: relative; } .codeInput { position: relative; z-index: 1; /* 保证和pre的字体、行高、内边距完全一致 */ font-family: monospace; font-size: 14px; line-height: 1.5; padding: 12px; color: transparent; caret-color: #2d2d2d; } .codeOutput { position: absolute; top: 0; left: 0; z-index: 0; pointer-events: none; margin: 0; /* 和textarea的字体、行高、内边距完全对齐 */ font-family: monospace; font-size: 14px; line-height: 1.5; padding: 12px; }
方案3:手动强制重置光标闪烁周期
如果以上优化仍未解决问题,可以在方向键触发时手动强制浏览器重置光标闪烁周期,在handleKeyDown中新增以下逻辑即可:
const handleKeyDown = (e) => { // 新增方向键处理逻辑 const directionKeys = ['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown', 'Home', 'End']; if (directionKeys.includes(e.key)) { const textarea = e.currentTarget; const originCaretColor = textarea.style.caretColor; // 临时修改后立即恢复,强制浏览器重绘光标 textarea.style.caretColor = 'transparent'; void textarea.offsetWidth; // 触发强制重绘 textarea.style.caretColor = originCaretColor || '#2d2d2d'; } // 原有Tab逻辑保持不变 // ... }
内容的提问来源于stack exchange,提问作者FlowRan
相关产品推荐
相关产品推荐

