🚀 极致体验!一个小工具实现智能关键词高亮 (中英文混排/全字匹配)
在前端开发中,"关键词高亮"是一个看似简单实则暗坑无数的需求。
你是否遇到过这些问题?
- 高亮"run"却把"running"也标红了? (英文全字匹配问题)
- 搜索"C++"导致正则报错崩溃? (特殊字符转义问题)
- 中文关键词死活匹配不上? (正则边界问题)
- 用
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 atestcase 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),以后遇到高亮需求,一秒搞定!💪