You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.27 06:24:03