在uni-app中用v-html高亮搜索关键词:先escaperegexp转义关键词,再用new regexp(keyword,'gi')全局替换并包裹,最后v-html渲染;rich-text不支持class/style,不可用。

uni-app里怎么让搜索关键词在文字中高亮?
直接用 v-html 渲染带 <span></span> 标签的 HTML 字符串是最常用、最可控的方式。uni-app 的 rich-text 组件虽然也能渲染富文本,但它对样式支持有限(比如不支持内联 style 或 class),且无法响应点击事件,所以实际项目中基本不用它做高亮。
关键点在于:先对原始文本做关键词替换,把匹配部分包进带样式的 <span></span>,再用 v-html 渲染。注意要转义原始文本中已有的 HTML 字符(如 &、),否则可能被误解析或 XSS。
- 用
String.prototype.replace()配合正则(记得加g和i标志)做全局、忽略大小写匹配 - 正则需用
new RegExp(keyword, 'gi')构造,避免关键词含特殊字符(如.、*)导致报错——得先对 keyword 做escapeRegExp处理 - 替换时用函数形式,确保只高亮纯文本匹配,不破坏已有标签结构(比如别把
<view>xxx</view>里的 xxx 也套上 span)
如何安全地 escape 搜索关键词中的正则特殊字符?
用户输入的关键词可能含 .、+、*、?、^、$ 等,直接塞进 new RegExp(keyword) 会语法错误。必须提前转义。
推荐这个轻量函数:
function escapeRegExp(string) {
return string.replace(/[.*+?^${}()|[]\]/g, '\$&');
}
用法示例:
const keyword = 'a.b+c'; const safeKeyword = escapeRegExp(keyword); // → 'a.b+c' const reg = new RegExp(safeKeyword, 'gi');
- 别用
keyword.replace(/[-/\^$*+?.()|[]{}]/g, '\$&')这类漏掉^或]的简版,容易出错 - 如果搜索支持多关键词(如空格分隔),要逐个
escapeRegExp后再拼正则,不要直接拼字符串 - uni-app 在 H5 和小程序平台表现一致,这个 escape 方案全端通用
为什么不能直接用 rich-text + 动态 class?
因为 rich-text 只接受静态 HTML 字符串,不支持绑定 class 或 style 属性。你传进去的 <span class="highlight">xxx</span>,class 会被忽略,样式不会生效。
常见错误写法:
<rich-text :nodes="highlightedText"></rich-text> // data 中 highlightedText = '<span class="highlight">abc</span>'
结果是文字照常显示,但没颜色、没背景——class 完全失效。
- 想用 CSS 控制高亮样式?只能走
v-html+ 内联style(如<span style="color: #f00; background: #ffeb3b;"></span>) - 小程序里
v-html不支持所有 HTML 标签(比如<div> 会被过滤),但 <code><span></span>安全可用 - H5 端没问题;App 端(vue2)需确认
v-html是否开启(默认开),vue3 版 App 也支持
点击高亮文字后怎么定位到对应 item?
v-html 渲染的内容无法直接绑定 @click,必须靠事件委托。给外层容器加 @click,然后判断 event.target 是否为高亮 <span></span>。
示例结构:
<view class="list"><view v-for="(item, i) in list" :key="i" class="item"><view v-html="highlight(item.text, keyword)"></view></view></view>
onHighlightClick 中判断:
onHighlightClick(e) {
const target = e.target;
if (target.tagName === 'SPAN' && target.style.color === 'rgb(255, 0, 0)') {
// 找到被点击的高亮项,向上找最近的 .item 元素
const itemNode = target.closest('.item');
const index = Array.from(itemNode.parentNode.children).indexOf(itemNode);
console.log('点击了第', index, '项的高亮文字');
}
}
- 不要依赖
className判断,小程序里 class 名可能被编译/压缩 - 用
style属性比 class 更可靠,但注意 color 值是 rgb 格式(不是 hex) - 如果高亮区域需要区分“词”和“整句”,建议在生成 HTML 时给
<span></span>加唯一data-keyword或data-index
escapeRegExp 和事件委托这两步,漏一个就导致白屏或点击失灵。











