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

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

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

你是否遇到过这些问题?

  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),以后遇到高亮需求,一秒搞定!💪

相关推荐
用户09340777351420 小时前
HarmonyOS WPS Open SDK 实践:用能力分层重构 OpenFileRequest
typescript·harmonyos
gis开发之家2 天前
vue3直击架构痛点 依赖倒置与接口隔离——打造坚如磐石的插件与高阶组件(HOC)模式
javascript·架构·typescript·前端框架·vue3
冬枳2 天前
基于OpenSeagragon封装的前端病理切片展示组件
前端·typescript
退休倒计时2 天前
【每日一题】LeetCode 287. 寻找重复数 TypeScript
算法·leetcode·typescript
@@@@@@@@543 天前
JavaScript 的缺点与 TypeScript 的弥补
开发语言·javascript·typescript
用户0934077735143 天前
HarmonyOS WPS Open SDK 实践:最小打开闭环与 enableEdit 分支处理
typescript·harmonyos
柯克七七4 天前
我把 bug 修得太干净了,测试组以为这个模块本来就没问题
前端·javascript·typescript
退休倒计时4 天前
【每日一题】LeetCode 39. 组合总和 TypeScript
算法·leetcode·typescript
yyt3630458414 天前
KlineChartQuant Tooltip 高频交互 200FPS 性能优化完整复盘
前端·经验分享·性能优化·typescript·vue·交互·chrome devtools
用户0934077735144 天前
HarmonyOS WPS Open SDK 实践:办公审批附件「打开—编辑—回传」代码实现
typescript·harmonyos