极致体验!一个小工具实现智能关键词高亮 (中英文混排/全字匹配)

🚀 极致体验!一个小工具实现智能关键词高亮 (中英文混排/全字匹配)

在前端开发中,"关键词高亮"是一个看似简单实则暗坑无数的需求。

你是否遇到过这些问题?

  1. 高亮"run"却把"running"也标红了? (英文全字匹配问题)
  2. 搜索"C++"导致正则报错崩溃? (特殊字符转义问题)
  3. 中文关键词死活匹配不上? (正则边界问题)
  4. dangerouslySetInnerHTML 总是提心吊胆? (XSS 安全问题)

今天,我将分享一个 不到 40 行代码 的终极解决方案 markWords。它不仅完美解决了上述所有问题,还支持 React 虚拟 DOM 直接渲染!


✨ 核心亮点

  • 智能匹配:英文自动开启"全字匹配",中文自动开启"模糊匹配"。
  • 安全无毒 :返回 React Node 数组,拒绝 dangerouslySetInnerHTML
  • 正则健壮 :自动转义 ?+* 等正则特殊字符。
  • 零依赖:不需要引入任何第三方库 (lodash, highlighting, etc)。

🛠️ 源码解析

直接将以下代码复制到你的 utils.ts 中:

ts 复制代码
import React from 'react';

/**
 * 智能标记文本中的关键词
 * 
 * 特性:
 * 1. 英文单词 -> 全字匹配 (如 "run" 不会匹配 "running")
 * 2. 中文/符号 -> 模糊匹配
 * 3. 自动转义正则特殊字符
 * 4. 返回 ReactNode 数组,安全无 XSS 风险
 *
 * @param {string} text - 原始文本
 * @param {string[]} words - 关键词数组
 * @param {string} highlightClass - 高亮类名
 */
export const markWords = (text, words, highlightClass = 'highlight') => {
  if (!text || !words || words.length === 0) {
    return [text];
  }

  // 1. 构造智能正则
  const pattern = words
    .map(word => {
      // 转义特殊字符,防止正则报错
      const escaped = word.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
      
      // 核心魔法:如果是纯英文/数字单词,加上 \b 边界实现全字匹配
      // 否则(如中文),直接匹配
      if (/^\w+$/.test(word)) {
        return `\\b${escaped}\\b`;
      }
      return escaped;
    })
    .join('|');
    
  if (!pattern) return [text];

  // 2. 全局忽略大小写匹配
  const regex = new RegExp(`(${pattern})`, 'gi');
  const parts = [];
  let lastIndex = 0;
  let match;

  // 3. 循环切割文本
  while ((match = regex.exec(text)) !== null) {
    // 推入普通文本
    if (match.index > lastIndex) {
      parts.push(text.slice(lastIndex, match.index));
    }
    // 推入高亮节点 (使用 React.createElement)
    parts.push(
      React.createElement('span', { key: match.index, className: highlightClass }, match[0])
    );
    lastIndex = match.index + match[0].length;
  }

  // 推入剩余文本
  if (lastIndex < text.length) {
    parts.push(text.slice(lastIndex));
  }

  return parts.length > 0 ? parts : [text];
};

💡 效果演示

场景一:英文全字匹配

关键词:["test"] 文本:"This is a test case for testing."

  • 结果 :只有 test 被高亮,testing 中的 test 不会被误伤。

场景二:中文混合匹配

关键词:["苹果", "Apple"] 文本:"我喜欢吃苹果,因为Apple很好吃。"

  • 结果苹果Apple 都会被精准高亮。

场景三:特殊字符

关键词:["C++"] 文本:"C++ is a powerful language."

  • 结果 :正则自动转义 +C++ 完美高亮,程序不会崩。

📖 最佳实践

在组件中直接调用即可,就像使用普通的字符串一样:

tsx 复制代码
import { markWords } from '@/utils/util';
import styles from './index.module.scss';

const Article = ({ title, content, searchKeyword }) => {
  return (
    <div className={styles.card}>
      {/* 高亮标题 */}
      <h3>{markWords(title, [searchKeyword], styles.highlight)}</h3>
      
      {/* 高亮正文 */}
      <p>{markWords(content, [searchKeyword], styles.highlight)}</p>
    </div>
  );
};**别忘了定义 CSS:**
.highlight {
  color: #ff4d4f;
  background-color: #fff1f0;
  font-weight: bold;
  border-radius: 2px;
}

📝 总结

这个小工具虽然简单,但细节满满。它在保证 安全性 的前提下,兼顾了 中英文语言特性代码健壮性

把这个函数收藏进你的代码片段库(Snippets),以后遇到高亮需求,一秒搞定!💪

相关推荐
Awu122716 小时前
⚡从零开发 Agent CLI(四):给 CLI 装上"LLM 引擎"
typescript·ai编程·claude
假如让我当三天老蒯2 天前
TypeScript 继续学习(学习用)
前端·面试·typescript
糖拌西瓜皮3 天前
Node.js工程化实践:包管理、TypeScript配置与代码质量
typescript·node.js
Bolt5 天前
TypeScript 7.0 来了:当 tsc 用 Go 重写之后
javascript·typescript·go
Flynt5 天前
装上TypeScript 7.0 RC之后,最让我意外不是10倍提速
typescript·visual studio code
疯狂SQL5 天前
手写高性能在线 JSON 工具|Web Worker 工程化打包 + 语法自动修复 + 多语言代码生成实战
typescript·json·next.js·web worker·前端性能优化·esbuild·源码实战
Momo__9 天前
TypeScript NoInfer<T>——精准控制泛型推断的工具类型
前端·typescript
退休倒计时10 天前
【每日一题】LeetCode 146. LRU 缓存 TypeScript
算法·leetcode·缓存·typescript
kyriewen11 天前
TypeScript 高级类型:我用 infer 写了一个类型安全的 EventBus,终于搞懂了泛型约束
前端·javascript·typescript
月光刺眼11 天前
Bun + TypeScript 后端入门:从类型约束到 LLM API 调用
后端·typescript