React.js中textarea输入时实时高亮指定关键字的实现方案咨询
React textarea 实时关键词高亮实现方案
原生 <textarea> 仅支持渲染纯文本,无法直接给局部文本添加样式,该场景的通用实现思路为双层重叠布局,上层用透明 textarea 承接用户输入,下层用富文本容器渲染高亮内容,两层样式完全对齐即可达到输入内容实时高亮的效果。
具体实现步骤
1. 基础布局结构
外层使用相对定位容器包裹两个子元素:
- 底层:富文本容器(如
<div>),负责渲染带高亮标记的内容,所有文本样式和 textarea 完全对齐 - 上层:
<textarea>组件,设置文字透明、光标颜色正常,背景透明,完全覆盖在底层容器上承接输入
2. 关键词匹配与高亮渲染逻辑
首先对包含特殊字符的关键词做正则转义,再将输入内容按关键词拆分,匹配到的内容包裹带高亮样式的标签即可:
// 关键词列表,支持动态扩展 const keywords = ['+project', '@context']; // 转义正则特殊字符(+、.、*等符号需要转义才能正常匹配) const escapedKeywords = keywords.map(k => k.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')); const matchRegex = new RegExp(`(${escapedKeywords.join('|')})`, 'g'); // 渲染高亮内容的逻辑 const renderHighlightedText = (inputContent) => { const contentParts = inputContent.split(matchRegex); return contentParts.map((part, index) => { if (keywords.includes(part)) { return <span key={index} className="highlight-tag">{part}</span> } return part; }) }
3. 滚动同步处理
当 textarea 内容过长出现滚动条时,需要将滚动位置同步给底层富文本容器,避免高亮位置错位:
const handleTextareaScroll = (e) => { const highlightContainer = document.querySelector('.highlight-layer'); if (highlightContainer) { highlightContainer.scrollTop = e.target.scrollTop; highlightContainer.scrollLeft = e.target.scrollLeft; } }
完整可运行代码示例
React 组件代码
import { useState } from 'react'; function HighlightTextarea() { const [inputValue, setInputValue] = useState(''); const keywords = ['+project', '@context']; const escapedKeywords = keywords.map(k => k.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')); const matchRegex = new RegExp(`(${escapedKeywords.join('|')})`, 'g'); const renderHighlighted = () => { const parts = inputValue.split(matchRegex); return parts.map((part, idx) => keywords.includes(part) ? <span key={idx} className="highlight-tag">{part}</span> : part ) }; const handleScroll = (e) => { const highlightEl = document.querySelector('.highlight-layer'); if (highlightEl) { highlightEl.scrollTop = e.target.scrollTop; highlightEl.scrollLeft = e.target.scrollLeft; } }; return ( <div className="textarea-wrapper"> <div className="highlight-layer">{renderHighlighted()}</div> <textarea value={inputValue} onChange={(e) => setInputValue(e.target.value)} onScroll={handleScroll} className="input-area" /> </div> ); } export default HighlightTextarea;
对应CSS代码
.textarea-wrapper { position: relative; width: 600px; min-height: 200px; border: 1px solid #ccc; border-radius: 4px; } .highlight-layer, .input-area { width: 100%; min-height: 200px; padding: 10px; font-size: 14px; line-height: 1.6; font-family: system-ui, sans-serif; word-break: break-all; white-space: pre-wrap; overflow: auto; box-sizing: border-box; } .highlight-layer { position: absolute; top: 0; left: 0; color: #333; pointer-events: none; } .highlight-tag { background-color: #ffeb3b; border-radius: 2px; padding: 0 2px; } .input-area { position: relative; z-index: 1; background: transparent; color: transparent; caret-color: #000; border: none; outline: none; resize: none; }
可选替代方案
如果不想自己实现双层布局,也可以使用 react-contenteditable 等可编辑div组件代替原生textarea,直接在可编辑容器内渲染高亮标签,但需要额外处理输入时的光标定位问题,避免输入过程中光标自动跳转到末尾。
内容的提问来源于stack exchange,提问作者Rafael Inácio
相关产品推荐
相关产品推荐

