Browse Source

feat(home): add search submit and clear functionality for shows section

优化首页作品搜索体验:
1. 新增防抖搜索逻辑,使用提交搜索状态避免实时请求
2. 添加搜索框清除按钮,支持一键清空搜索内容
3. 支持回车触发搜索,优化交互体验
4. 新增搜索框聚焦边框样式,提升可交互辨识度
feature/group
huangmin 1 month ago
parent
commit
4bbd72c8de
  1. 47
      src/components/HomeProjectsContent.tsx

47
src/components/HomeProjectsContent.tsx

@ -1283,6 +1283,7 @@ function ShowsSection() {
]); ]);
const [dataList, setDataList] = useState<ShowData[]>([]); const [dataList, setDataList] = useState<ShowData[]>([]);
const [searchQuery, setSearchQuery] = useState(""); const [searchQuery, setSearchQuery] = useState("");
const [submittedSearchQuery, setSubmittedSearchQuery] = useState("");
const selectedCategoryId = categoryList[activeTab]?.id ?? null; const selectedCategoryId = categoryList[activeTab]?.id ?? null;
const [isCreating, setIsCreating] = useState(false); const [isCreating, setIsCreating] = useState(false);
const [isLoadingShows, setIsLoadingShows] = useState(false); const [isLoadingShows, setIsLoadingShows] = useState(false);
@ -1359,7 +1360,7 @@ function ShowsSection() {
setIsLoadingShows(true); setIsLoadingShows(true);
try { try {
const params = new URLSearchParams({ const params = new URLSearchParams({
keyword: searchQuery, keyword: submittedSearchQuery,
categoryId: selectedCategoryId ? String(selectedCategoryId) : "", categoryId: selectedCategoryId ? String(selectedCategoryId) : "",
type: "", type: "",
userId: "", userId: "",
@ -1411,7 +1412,7 @@ function ShowsSection() {
setIsLoadingShows(false); setIsLoadingShows(false);
} }
} }
}, [searchQuery, selectedCategoryId, t]); }, [submittedSearchQuery, selectedCategoryId, t]);
useEffect(() => { useEffect(() => {
const controller = new AbortController(); const controller = new AbortController();
@ -1421,12 +1422,9 @@ function ShowsSection() {
page: 1, page: 1,
pageSize: SHOWS_PAGE_SIZE, pageSize: SHOWS_PAGE_SIZE,
}); });
const timeout = window.setTimeout(() => { void loadShowsPage(1, { signal: controller.signal });
void loadShowsPage(1, { signal: controller.signal });
}, 250);
return () => { return () => {
window.clearTimeout(timeout);
controller.abort(); controller.abort();
loadingMoreShowsPageRef.current = null; loadingMoreShowsPageRef.current = null;
}; };
@ -1444,6 +1442,15 @@ function ShowsSection() {
}); });
}, [isLoadingShows, loadShowsPage, showsPage, showsPageInfo.pageCount]); }, [isLoadingShows, loadShowsPage, showsPage, showsPageInfo.pageCount]);
const handleSubmitSearch = useCallback(() => {
setSubmittedSearchQuery(searchQuery.trim());
}, [searchQuery]);
const handleClearSearch = useCallback(() => {
setSearchQuery("");
setSubmittedSearchQuery("");
}, []);
useEffect(() => { useEffect(() => {
const handleScroll = () => { const handleScroll = () => {
if (!canLoadMoreShows || isLoadingShows) return; if (!canLoadMoreShows || isLoadingShows) return;
@ -1506,14 +1513,38 @@ function ShowsSection() {
))} ))}
</div> </div>
</div> </div>
<div className="flex h-[35px] w-full items-center justify-between rounded-full bg-white px-[15px] text-[#999] shadow-[0_2px_5px_rgba(0,0,0,0.1)] lg:w-[295px]"> <div className="flex h-[35px] w-full items-center justify-between rounded-full border border-transparent bg-white px-[15px] text-[#999] shadow-[0_2px_5px_rgba(0,0,0,0.1)] transition focus-within:border-[#5c3bc7] lg:w-[295px]">
<input <input
value={searchQuery} value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)} onChange={(e) => setSearchQuery(e.target.value)}
onKeyDown={(event) => {
if (event.key === "Enter") {
handleSubmitSearch();
}
}}
placeholder={t("home.searchPlaceholder")} placeholder={t("home.searchPlaceholder")}
className="min-w-0 flex-1 bg-transparent text-[14px] outline-none placeholder:text-[#999]" className="min-w-0 flex-1 bg-transparent text-[14px] outline-none placeholder:text-[#999]"
/> />
<SearchIcon /> {searchQuery ? (
<button
type="button"
onClick={handleClearSearch}
aria-label={t("common.clear")}
title={t("common.clear")}
className="mr-1 grid h-7 w-7 shrink-0 place-items-center rounded-full text-[#999] transition hover:bg-[#f0f0f0] hover:text-[#666]"
>
<CloseIcon />
</button>
) : null}
<button
type="button"
onClick={handleSubmitSearch}
aria-label={t("home.searchPlaceholder")}
title={t("home.searchPlaceholder")}
className="grid h-7 w-7 shrink-0 place-items-center rounded-full text-[#999] transition hover:bg-[#f0f0f0] hover:text-[#5c3bc7]"
>
<SearchIcon />
</button>
</div> </div>
</div> </div>
<div className="grid gap-5 md:grid-cols-2 xl:grid-cols-4"> <div className="grid gap-5 md:grid-cols-2 xl:grid-cols-4">

Loading…
Cancel
Save