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

React Autocomplete如何实现自动补全结果中匹配输入字符的黄色高亮

自动补全匹配文本高亮实现方案

实现要点

  • 保留现有大小写不敏感的过滤规则,文本比对时统一转小写处理,渲染时完全保留原姓名的原始大小写,不修改源文本的格式
  • 自动识别文本中所有和搜索词匹配的连续片段,不管匹配位置在开头、中间还是结尾,都会被设置黄色背景高亮
  • 对搜索词中的正则特殊字符做转义处理,避免用户输入.、*、?这类字符时出现匹配报错
  • 处理空搜索词的边界情况,搜索为空时不触发高亮逻辑,直接展示原始文本

代码改造步骤

1. 新增工具函数

在App组件内部新增两个函数,分别用于正则转义和高亮文本渲染:

// 转义搜索词中的正则特殊字符,避免匹配逻辑异常
const escapeRegExp = (str) => str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');

// 渲染带高亮的文本内容
const renderHighlight = (originalText, query) => {
  const trimmedQuery = query.trim();
  // 搜索词为空时直接返回原文本
  if (!trimmedQuery) return originalText;
  // 构造大小写不敏感的全局匹配正则
  const regex = new RegExp(`(${escapeRegExp(trimmedQuery)})`, 'ig');
  // 按匹配结果拆分字符串
  const textParts = originalText.split(regex);
  
  return textParts.map((part, index) => {
    // 匹配到的片段套高亮样式
    if (part.toLowerCase() === trimmedQuery.toLowerCase()) {
      return <span key={index} className="match-highlight">{part}</span>;
    }
    // 非匹配片段正常渲染
    return <React.Fragment key={index}>{part}</React.Fragment>;
  });
};

2. 补充高亮样式

在App.css中新增高亮类的样式定义:

/* 匹配文本黄色背景样式 */
.match-highlight {
  background-color: #fff100;
  padding: 0 1px;
  border-radius: 2px;
}

3. 替换列表渲染逻辑

将原来自动补全列表中直接渲染姓名的部分,替换为调用高亮渲染函数的逻辑:

{/* 原逻辑:<li key={value.name}>{value.name}</li> */}
{filteredName.map((value) => (
  <li key={value.name}>
    {renderHighlight(value.name, searchTerm)}
  </li>
))}

完整可运行代码

import logo from './logo.svg';
import './App.css';
import React, { useState } from "react";

function App() {
  const [names, setnames] = useState([
    { "name": "Barbara-anne" }, { "name": "Debi" }, { "name": "Cara" },
    { "name": "Cristin" }, { "name": "Jocelyne" }, { "name": "Joellyn" },
    { "name": "Elmo" }, { "name": "Ivette" }, { "name": "Lea" },
    { "name": "Michel" }, { "name": "Leigha" }, { "name": "Titus" },
    { "name": "Nollie" }, { "name": "Celle" }, { "name": "Thea" },
    { "name": "Brynn" }, { "name": "Sloane" }, { "name": "Margalo" },
    { "name": "Genevieve" }, { "name": "Niel" }, { "name": "Heddi" },
    { "name": "Gregg" }, { "name": "Eduard" }, { "name": "Kizzee" },
    { "name": "Truman" }, { "name": "Merill" }, { "name": "Lindie" },
    { "name": "Vasily" }, { "name": "Averil" }, { "name": "Golda" },
    { "name": "Zorine" }, { "name": "Odele" }, { "name": "Amalie" },
    { "name": "Ilsa" }, { "name": "Pepillo" }, { "name": "Hewe" },
    { "name": "Byrann" }, { "name": "Alford" }, { "name": "Lanny" },
    { "name": "Kristina" }, { "name": "Mar" }, { "name": "Vittoria" },
    { "name": "Winslow" }, { "name": "Ashlan" }, { "name": "Gayelord" }
  ])
  const [searchTerm, setSearchTerm] = useState('')

  const filteredName = names.filter((val) => {
    if (searchTerm === "") {
      return true;
    } else if (val.name.toLowerCase().includes(searchTerm.toLowerCase())) {
      return true;
    }
    return false;
  });

  // 正则特殊字符转义函数
  const escapeRegExp = (str) => str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');

  // 高亮文本渲染函数
  const renderHighlight = (originalText, query) => {
    const trimmedQuery = query.trim();
    if (!trimmedQuery) return originalText;
    const regex = new RegExp(`(${escapeRegExp(trimmedQuery)})`, 'ig');
    const textParts = originalText.split(regex);
    
    return textParts.map((part, index) => {
      if (part.toLowerCase() === trimmedQuery.toLowerCase()) {
        return <span key={index} className="match-highlight">{part}</span>;
      }
      return <React.Fragment key={index}>{part}</React.Fragment>;
    });
  };

  const renderStatementResult = searchTerm && searchTerm.length > 0;
  return (
    <>
      <div className="srchField">
        <label for="statement">Statement Name</label>
        <div className="valueField">
          <input 
            type="text" 
            name="fileName" 
            id="statement" 
            data-validate="true" 
            placeholder="Type Name" 
            onChange={event => {setSearchTerm(event.target.value)}}
          />
          {
            renderStatementResult ? 
            <ul className="lookup-results">
              {filteredName.map((value) => (
                <li key={value.name}>
                  {renderHighlight(value.name, searchTerm)}
                </li>
              ))}
            </ul> : null
          }
        </div>
      </div>
    </>
  );
}

export default App;

实现效果说明:输入任意搜索内容后,自动补全列表中所有和输入内容匹配的字符片段都会被黄色背景高亮,全程保留原文本的大小写格式,不会出现文本变形的问题。如果同一个姓名中多次出现和搜索词匹配的片段,所有匹配位置都会被自动高亮。

内容的提问来源于stack exchange,提问作者rasmi

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.22 17:45:07