React.js中如何给搜索结果匹配关键词单独设置样式并解决相关报错
问题1:span标签渲染为[object Object]
根因:String.prototype.replace 仅支持传入字符串作为替换值,你传入的<span>是JSX对象,被自动转为字符串后就会输出[object Object]。
解决方法:将文本按搜索词切割为数组,遍历数组为匹配到的片段包裹样式标签,返回React可直接渲染的混合文本/元素数组,参考函数实现:
const highlightMatch = (text, query) => { // 搜索词为空时直接返回处理后的原文本 if (!query.trim()) return text.replace(/- /g, "").replace(/\./g, ""); // 用括号包裹正则匹配项,split时会保留匹配项本身 const re = new RegExp(`(${query})`, "ig"); const parts = text.replace(/- /g, "").replace(/\./g, "").split(re); // 过滤空片段后遍历生成内容 return parts.filter(Boolean).map((part, idx) => { return part.toLowerCase() === query.toLowerCase() ? <span key={idx} className="boldFont">{part}</span> : part; }); };
问题2:列表key警告
根因:两处遍历生成元素列表时未添加唯一key属性:
- 遍历
searchResults生成<li>标签时未加key - 上述高亮函数中生成的span元素作为数组项也需要加key(上面的函数实现已经补充了key)
修改后完整代码
import React, { Fragment } from "react"; import CancelIcon from "@material-ui/icons/Cancel"; import CallMadeIcon from "@material-ui/icons/CallMade"; export default function SearchBar(props) { // 把高亮函数提出来避免每次渲染重复声明 const highlightMatch = (text, query) => { if (!query.trim()) return text.replace(/- /g, "").replace(/\./g, ""); const re = new RegExp(`(${query})`, "ig"); const parts = text.replace(/- /g, "").replace(/\./g, "").split(re); return parts.filter(Boolean).map((part, idx) => { return part.toLowerCase() === query.toLowerCase() ? <span key={idx} className="boldFont">{part}</span> : part; }); }; return ( <Fragment> <div className="search"> <div className="search-input-container" ref={props.searchInputContainerRef} > <label htmlFor="search-input"></label> <input type="text" id="search-input" placeholder={props.placeholder} onChange={props.handleSetSearchTerm} value={props.searchTerm} ref={props.searchInputRef} onFocus={props.blurAllOnSearch} onBlur={props.blurAllOnSearch} onKeyUp={props.handleFilter} /> {props.searchTerm === "" ? ( <button ref={props.searchIconVectorRef} type="button" className="search-icon-btn" onClick={props.focusSearchInput} ></button> ) : ( <CancelIcon className="clear-btn" type="button" onClick={props.clearSearchInput} /> )} <button className="go-search-btn">Go</button> </div> {props.searchResults.length !== 0 && ( <div className="search-results"> {/* 给li添加key,优先用搜索结果的唯一业务id比如value.id,没有的话再用index */} {props.searchResults.slice(0, 15).map((value, index) => { let bolded = highlightMatch(value.title, props.searchTerm); return ( <li key={value.id || index} className="data-item"> <a className="result" href={value.link} target="_blank" rel="noreferrer" > {bolded} </a> <CallMadeIcon className="call-made-icon" /> </li> ); })} </div> )} </div> </Fragment> ); }
后续你可以直接通过CSS修改.boldFont类的样式实现自定义高亮效果。
内容的提问来源于stack exchange,提问作者Klem Lloyd Mwenya
相关产品推荐
相关产品推荐

