我有一个搜索组件,它根据 searchTerm 从 SlideData 返回数据。我的目标是突出显示输入的单词。我想我需要使用indexOf或标签,但我正在努力思考在哪里使用它的逻辑?为了清楚起见,预期的结果是,如果我搜索“汉堡包”,它将显示带有汉堡包的所有结果,并在这些结果中突出显示“汉堡包”。
const [searchTerm, setSearchTerm] = useState("");
const SlideData = [
{
slideIndex: 1,
title: "My name is Bob",
text1: "Bob likes to eat hamburgers",
text2: "Kenny likes to eat hot dogs",
text3: "Terry likes milkshakes"
},
{
slideIndex: 2,
title: "My name is Jill",
text1: "Jill likes to eat hamburgers",
text2: "Joshua likes to eat hot dogs",
text3: "Steven likes milkshakes"
}
]
<div className="search-results">
<ul className="search-list">
{SlideData.filter((item) => {
if (searchTerm === "") {
return null;
} else {
//concat the text properties into variable//
let searchText = item.title + item.text1 + item.text2 + item.text3 + item.text4;
//if the variable contains the search term value//
if (searchText.toLowerCase().includes(searchTerm.toLowerCase())) {
//return those items//
return item;
}
}
}).map((item) => (
//map through the items and display list of results
<div key={item.slideIndex} style={{ marginTop: "20px" }}>
<h4 style={{ color: "white" }}>{item.title}</h4>
<li className="search-item">{item.text1}</li>
<li className="search-item">{item.text1.indexOf(searchTerm)}</li>
<a
className="search-link"
onClick={() => {
context.setCurrentSlide(item.slideIndex);
setSearchTerm("");
}}
>
Go To Slide {item.slideIndex}
</a>
</div>
))}
</ul>
</div>
我正在尝试的事情
//find the search term in the results//
const highlighted = item.text1.indexOf(searchTerm);
if(searchTerm === -1){
//highlight the term
}else{
//Do nothing
}
为了使用不同的样式来定位结果,您需要将其分解为自己的 HTML 元素。
您可以使用这个正则表达式函数
const splitResult = (result) =>
//Split on search result and then simply style the matches
result.split(new RegExp(`(${searchTerm})`, `gi`)).map((piece, index) => {
return (
<span
key={index}
style={{
background:
piece.toLowerCase() === searchTerm.toLocaleLowerCase()
? "YELLOW"
: "TRANSPARENT"
}}
>
{piece}
</span>
);
});
这是您的完整组件,我删除了一些与问题无关的部分
export default function App() {
const [searchTerm, setSearchTerm] = useState("");
const splitResult = (result) =>
//Split on search result and then simply style the matches then map through
result.split(new RegExp(`(${searchTerm})`, `gi`)).map((piece, index) => {
return (
<span
key={index}
style={{
background:
piece.toLowerCase() === searchTerm.toLocaleLowerCase()
? "YELLOW"
: "TRANSPARENT"
}}
>
{piece}
</span>
);
});
return (
<div className="search-results">
<ul className="search-list">
{/** Search input */}
<input
type="search"
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
/>
{SlideData.filter((item) => {
if (searchTerm === "") {
return null;
} else {
//concat the text properties into variable//
let searchText = item.title + item.text1 + item.text2 + item.text3 + item.text4;
//if the variable contains the search term value//
if (searchText.toLowerCase().includes(searchTerm.toLowerCase())) {
//return those items//
return item;
}
}
return null;
}).map((item) => (
//map through the items and display list of results
<div key={item.slideIndex} style={{ marginTop: "20px" }}>
<h4>{item.title}</h4>
<li>{splitResult(item.text1)}</li>
<li>{item.text1.indexOf(searchTerm)}</li>
</div>
))}
</ul>
</div>
);
}
我将使用原生的 CSS 自定义突出显示 API 以命令式方式执行此操作。优点是 DOM 不会因选择而修改,不涉及 React,并且除了
useEffect
: 之外不需要任何其他逻辑
import { useEffect, useState } from "react";
import { highlightSearchTerm } from "highlight-search-term";
export default function App() {
const [search, setSearch] = useState("");
useEffect(() => {
highlightSearchTerm({ search, selector: ".search-results" });
}, [search]);
return (
<div>
<input
type="text"
value={search}
onChange={(e) => setSearch(e.target.value)}
/>
<div className="search-results">
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
</div>
</div>
);
}