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

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

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

你是否遇到过这些问题?

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

相关推荐
VT.馒头21 分钟前
【力扣】2625. 扁平化嵌套数组
前端·javascript·算法·leetcode·职场和发展·typescript
San30.3 小时前
从零构建坚固的前端堡垒:TypeScript 与 React 实战深度指南
前端·react.js·typescript
VT.馒头5 小时前
【力扣】2694. 事件发射器
前端·javascript·算法·leetcode·职场和发展·typescript
止观止6 小时前
像三元表达式一样写类型?深入理解 TS 条件类型与 `infer` 推断
前端·typescript
We་ct7 小时前
LeetCode 73. 矩阵置零:原地算法实现与优化解析
前端·算法·leetcode·矩阵·typescript
We་ct7 小时前
LeetCode 48. 旋转图像:原地旋转最优解法
前端·算法·leetcode·typescript
We་ct1 天前
LeetCode 54. 螺旋矩阵:两种解法吃透顺时针遍历逻辑
前端·算法·leetcode·矩阵·typescript
We་ct1 天前
LeetCode 36. 有效的数独:Set实现哈希表最优解
前端·算法·leetcode·typescript·散列表
Async Cipher2 天前
TypeScript 的用法
前端·typescript
We་ct2 天前
LeetCode 30. 串联所有单词的子串:从暴力到高效,滑动窗口优化详解
前端·算法·leetcode·typescript