下面整理一篇关于 Vue 3 中实现搜索框检索高亮的文章,涵盖思路、实现步骤、完整代码示例及常用优化方案。
前言
在日常后台系统或内容型产品中,搜索关键词高亮 是一项非常常见的需求。用户在搜索框输入文字后,列表中匹配的内容需要将关键词部分以醒目的样式(如黄色背景)标记出来,帮助用户快速定位。
本文将基于 Vue 3 的组合式 API,从零实现一个支持实时搜索 与关键词高亮的功能组件,并附上可直接使用的代码与优化建议。
效果预览
- 输入关键词,列表实时过滤出包含关键词的条目
- 匹配到的文字自动高亮(可自定义样式)
- 支持多个关键词高亮
- 支持忽略大小写
- 组件化、可复用

思路分析
整体实现可以拆分为三个核心点:
- 数据过滤:根据输入的关键词,对列表数据进行筛选。
- 高亮渲染 :将匹配到的关键词用
<span>等标签包裹,并通过 CSS 类名添加高亮样式。 - 安全性 :避免直接使用
v-html造成的 XSS 风险(需要对用户输入进行转义,但在纯前端本地搜索场景一般风险可控;若数据来源包含用户生成内容,则必须转义)。
实现的关键函数是:将文本中的关键词替换为带高亮标签的 HTML 字符串 ,然后通过 v-html 渲染。
实现步骤与代码
1. 基础搜索组件结构
我们创建一个 SearchHighlight.vue 组件,包含一个搜索框和一个结果列表。
vue
<template>
<div class="search-container">
<input
v-model="keyword"
type="text"
placeholder="请输入关键词搜索..."
class="search-input"
/>
<ul class="list">
<li
v-for="item in filteredList"
:key="item.id"
class="list-item"
>
<!-- 这里使用 v-html 渲染高亮文本 -->
<span v-html="highlightText(item.name)"></span>
</li>
</ul>
<div v-if="!filteredList.length" class="empty">无匹配结果</div>
</div>
</template>
2. 编写组合式逻辑
vue
<script setup>
import { ref, computed } from 'vue'
// 原始数据(模拟)
const originalList = [
{ id: 1, name: 'Vue 3 组合式 API 实战' },
{ id: 2, name: 'React Hooks 深入浅出' },
{ id: 3, name: 'JavaScript 高级程序设计' },
{ id: 4, name: 'TypeScript 类型体操' },
{ id: 5, name: 'Vue 与 React 对比' },
]
const keyword = ref('')
// 过滤后的列表(忽略大小写)
const filteredList = computed(() => {
const kw = keyword.value.trim().toLowerCase()
if (!kw) return originalList
return originalList.filter((item) =>
item.name.toLowerCase().includes(kw)
)
})
/**
* 高亮文本处理函数
* @param text 原始文本
* @returns 包含高亮 span 的 HTML 字符串
*/
function highlightText(text) {
const kw = keyword.value.trim()
if (!kw) return text
// 1. 对特殊正则字符进行转义,防止正则报错
const escapedKw = escapeRegExp(kw)
// 2. 创建全局、忽略大小写的正则
const regex = new RegExp(`(${escapedKw})`, 'gi')
// 3. 替换为带高亮类的 span
return text.replace(regex, '<span class="highlight">$1</span>')
}
/**
* 转义正则特殊字符
*/
function escapeRegExp(string) {
return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
}
</script>
3. 添加样式
vue
<style scoped>
.search-container {
max-width: 500px;
margin: 20px auto;
font-family: 'Segoe UI', sans-serif;
}
.search-input {
width: 100%;
padding: 12px 16px;
font-size: 16px;
border: 1px solid #ccc;
border-radius: 8px;
outline: none;
transition: border 0.2s;
}
.search-input:focus {
border-color: #4a90e2;
}
.list {
list-style: none;
padding: 0;
margin-top: 16px;
}
.list-item {
padding: 10px 12px;
border-bottom: 1px solid #eee;
}
.empty {
text-align: center;
color: #999;
margin-top: 20px;
}
/* 高亮样式 */
:deep(.highlight) {
background-color: #ffeb3b;
color: #333;
font-weight: 600;
border-radius: 2px;
padding: 0 2px;
}
</style>
注意:因为高亮的
<span>是通过v-html动态插入的,scoped 样式无法直接作用到动态内容上,所以这里使用了:deep()或直接写全局样式(若组件隔离要求不高,可用全局 class)。
4. 完整组件代码
将上述模板、脚本、样式合并,即可得到一个完整的 SearchHighlight.vue 组件。在父组件中直接引入使用即可。
vue
<template>
<SearchHighlight />
</template>
功能扩展与优化
支持多个关键词高亮
有时需求允许用户输入多个关键词(如用空格分隔),每个关键词都高亮。只需调整 highlightText 函数:
javascript
function highlightText(text) {
const keywords = keyword.value.trim().split(/\s+/).filter(Boolean)
if (!keywords.length) return text
// 将多个关键词用 | 连接,构建一个正则表达式
const escaped = keywords.map(escapeRegExp).join('|')
const regex = new RegExp(`(${escaped})`, 'gi')
return text.replace(regex, '<span class="highlight">$1</span>')
}
防止 XSS 攻击
如果高亮的文本内容可能包含用户输入的 HTML(例如用户名被恶意注入),直接使用 v-html 会有风险。安全的做法是:
javascript
function escapeHtml(str) {
return str
.replace(/&/g, '&')
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/"/g, '"')
.replace(/'/g, ''')
}
function highlightText(text) {
const safeText = escapeHtml(text) // 先转义原文
const kw = escapeHtml(keyword.value.trim()) // 关键词也转义
if (!kw) return safeText
const escapedKw = escapeRegExp(kw)
const regex = new RegExp(`(${escapedKw})`, 'gi')
return safeText.replace(regex, '<span class="highlight">$1</span>')
}
这样就杜绝了潜在脚本注入的可能。
虚拟滚动优化
当列表数据量很大时,频繁的 DOM 更新可能造成卡顿。可以结合虚拟滚动库(如 vue-virtual-scroller)只渲染可视区域内的节点,大幅提升性能。
防抖搜索
如果过滤逻辑非常复杂(比如前端模糊搜索大数据集),可以对 keyword 的更新做防抖,减少 computed 触发频率:
javascript
import { ref, watch } from 'vue'
import { useDebounceFn } from '@vueuse/core' // 或自行实现
const keyword = ref('')
const debouncedKeyword = ref('')
const updateKeyword = useDebounceFn((val) => {
debouncedKeyword.value = val
}, 300)
watch(keyword, (val) => updateKeyword(val))
// 之后的过滤和高亮都基于 debouncedKeyword 进行计算
总结
通过上述方法,我们实现了一个简洁、实用且安全的 Vue 3 搜索高亮功能。核心在于:
- 使用
computed实时过滤数据 - 使用正则替换生成高亮 HTML,并通过
v-html渲染 - 注意转义特殊字符和 XSS 防护
- 可按需扩展多关键词、虚拟滚动、防抖等功能
这种模式可以轻松封装成通用组件或组合式函数,在各个项目中复用,大幅提升开发效率与用户体验。
------个人观点 · 仅供参考------