React Native搜索结果自定义:如何高亮匹配关键词?
React Native 搜索关键词高亮实现方案
要实现搜索关键词高亮,核心是把包含搜索词的文本拆分为「普通文本」和「匹配关键词」两部分,分别用不同样式渲染。React Native 的 <Text> 组件支持嵌套,我们可以通过字符串拆分+正则匹配来实现。
步骤1:编写高亮处理工具函数
先写一个通用函数,接收原始文本和搜索词,返回带高亮样式的文本片段数组:
const highlightText = (text, searchTerm) => { if (!searchTerm.trim()) return <Text>{text}</Text>; // 转义正则特殊字符,避免搜索词含特殊字符时报错 const escapedSearchTerm = searchTerm.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // 大小写不敏感匹配 const regex = new RegExp(`(${escapedSearchTerm})`, 'gi'); // 拆分文本为普通片段和匹配片段 const parts = text.split(regex); return parts.map((part, index) => { // 判断当前片段是否匹配搜索词(大小写不敏感) const isMatch = part.toLowerCase() === searchTerm.toLowerCase(); return ( <Text key={index} style={isMatch ? listStyles.highlightedText : {}}> {part} </Text> ); }); };
步骤2:修改组件代码
替换原代码中渲染匹配文本的逻辑,同时修复原代码中 keyWord 变量作用域的问题(原代码循环会覆盖 keyWord,导致只显示最后一个匹配的 stanza):
import { View, Text, ScrollView, SafeAreaView, BackHandler, } from "react-native"; import React from "react"; import { hymnsCollection } from "./data"; import styles from "../../styles/App"; import listStyles from "./Styles"; import { useNavigation } from "@react-navigation/native"; const List = ({ searchFilter }) => { const navigation = useNavigation(); const data = hymnsCollection; // 高亮处理函数 const highlightText = (text, searchTerm) => { if (!searchTerm.trim()) return <Text>{text}</Text>; const escapedSearchTerm = searchTerm.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); const regex = new RegExp(`(${escapedSearchTerm})`, 'gi'); const parts = text.split(regex); return parts.map((part, index) => { const isMatch = part.toLowerCase() === searchTerm.toLowerCase(); return ( <Text key={index} style={isMatch ? listStyles.highlightedText : {}}> {part} </Text> ); }); }; return ( <SafeAreaView> <ScrollView> <View style={styles.container2}> <View style={styles.container3}> {data .filter((val) => { // 优化过滤逻辑:检查stanza或id是否匹配 const hasMatchingStanza = val.stanzas.some(e => e.toLowerCase().includes(searchFilter.toLowerCase()) ); const hasMatchingId = val.id.toString().includes(searchFilter); return hasMatchingStanza || hasMatchingId; }) .map((datas) => { // 用datas.id作为key更可靠 return searchFilter === "" ? ( <View key={datas.id}> <Text style={styles.hymnTitle} onPress={() => { navigation.navigate("content", { info: data, id: datas.id, }); }} selectable={true} > <Text style={styles.hymnNumber}>{`${datas.id} - `}</Text> <Text style={styles.hymnTitle} selectable={true}> {datas.title} </Text> </Text> </View> ) : ( <View key={datas.id} style={listStyles.container}> <Text onPress={() => { navigation.navigate("content", { info: data, id: datas.id, }); }} > <Text style={listStyles.hymnNumber}>{`${datas.id} - `}</Text> <Text style={listStyles.hymnTitle} selectable={true}> {highlightText(datas.title, searchFilter)} {"\n"} </Text> {/* 渲染所有匹配的stanza,而不是最后一个 */} {datas.stanzas.map((stanza, stanzaIndex) => { if (stanza.toLowerCase().includes(searchFilter.toLowerCase())) { return ( <Text key={stanzaIndex} style={listStyles.hymncontents}> {highlightText(stanza, searchFilter)} {"\n"} </Text> ); } return null; })} </Text> </View> ); })} </View> </View> </ScrollView> </SafeAreaView> ); }; export default List;
步骤3:添加高亮样式
在你的 listStyles 文件中添加高亮样式,比如:
const listStyles = StyleSheet.create({ // ... 原有样式 highlightedText: { backgroundColor: 'yellow', fontWeight: 'bold', }, });
关键优化点
- 修复了原代码中
keyWord变量被循环覆盖的问题,现在会渲染所有匹配的 stanza - 使用
datas.id作为列表项的 key,比索引更稳定 - 优化了过滤逻辑,用
some替代map,性能更好 - 处理了正则特殊字符的转义,避免搜索词含
.、*等字符时出错 - 同时支持标题和stanza中的关键词高亮
内容的提问来源于stack exchange,提问作者Wizard Chiboy
相关产品推荐
相关产品推荐

