From 3ae85e55f6699971199110945bc682d8bc49cbdd Mon Sep 17 00:00:00 2001 From: "tangly1024.com" Date: Mon, 27 May 2024 18:21:27 +0800 Subject: [PATCH] =?UTF-8?q?AlgoliaModal=20=E4=BA=A4=E4=BA=92=E4=BC=98?= =?UTF-8?q?=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- components/AlgoliaSearchModal.js | 278 +++++++++++++++++++------------ 1 file changed, 170 insertions(+), 108 deletions(-) diff --git a/components/AlgoliaSearchModal.js b/components/AlgoliaSearchModal.js index ea727a48..eac9d8bf 100644 --- a/components/AlgoliaSearchModal.js +++ b/components/AlgoliaSearchModal.js @@ -1,11 +1,18 @@ -import { useState, useImperativeHandle, useRef, useEffect, Fragment } from 'react' -import algoliasearch from 'algoliasearch' import replaceSearchResult from '@/components/Mark' -import Link from 'next/link' -import { useGlobal } from '@/lib/global' -import throttle from 'lodash/throttle' import { siteConfig } from '@/lib/config' -import { useHotkeys } from 'react-hotkeys-hook'; +import { useGlobal } from '@/lib/global' +import algoliasearch from 'algoliasearch' +import throttle from 'lodash/throttle' +import Link from 'next/link' +import { useRouter } from 'next/router' +import { + Fragment, + useEffect, + useImperativeHandle, + useRef, + useState +} from 'react' +import { useHotkeys } from 'react-hotkeys-hook' const ShortCutActions = [ { @@ -20,7 +27,6 @@ const ShortCutActions = [ key: 'Esc', action: '关闭' } - ] /** @@ -36,31 +42,49 @@ export default function AlgoliaSearchModal({ cRef }) { const [totalPage, setTotalPage] = useState(0) const [totalHit, setTotalHit] = useState(0) const [useTime, setUseTime] = useState(0) - const inputRef = useRef(null) const [activeIndex, setActiveIndex] = useState(0) const [isLoading, setIsLoading] = useState(false) - useHotkeys('ctrl+k', (e) => { + const inputRef = useRef(null) + const router = useRouter() + + /** + * 快捷键设置 + */ + useHotkeys('ctrl+k', e => { e.preventDefault() setIsModalOpen(true) }) // 方向键调整选中 - useHotkeys('down', (e) => { - e.preventDefault() - if (activeIndex < searchResults.length - 1) { - setActiveIndex(activeIndex + 1) - } - }, { enableOnFormTags: true }) - useHotkeys('up', (e) => { - e.preventDefault() - if (activeIndex > 0) { - setActiveIndex(activeIndex - 1) - } - }, { enableOnFormTags: true }) + useHotkeys( + 'down', + e => { + e.preventDefault() + if (activeIndex < searchResults.length - 1) { + setActiveIndex(activeIndex + 1) + } + }, + { enableOnFormTags: true } + ) + useHotkeys( + 'up', + e => { + e.preventDefault() + if (activeIndex > 0) { + setActiveIndex(activeIndex - 1) + } + }, + { enableOnFormTags: true } + ) // esc关闭 - useHotkeys('esc', (e) => { - e.preventDefault() - setIsModalOpen(false) - }, { enableOnFormTags: true }) + useHotkeys( + 'esc', + e => { + e.preventDefault() + setIsModalOpen(false) + }, + { enableOnFormTags: true } + ) + // 跳转Search结果 const onJumpSearchResult = () => { if (searchResults.length > 0) { @@ -68,11 +92,15 @@ export default function AlgoliaSearchModal({ cRef }) { } } // enter跳转 - useHotkeys('enter', (e) => { - if (searchResults.length > 0) { - onJumpSearchResult(index) - } - }, { enableOnFormTags: true }) + useHotkeys( + 'enter', + e => { + if (searchResults.length > 0) { + onJumpSearchResult(index) + } + }, + { enableOnFormTags: true } + ) const resetSearch = () => { setActiveIndex(0) @@ -84,6 +112,16 @@ export default function AlgoliaSearchModal({ cRef }) { if (inputRef.current) inputRef.current.value = '' } + /** + * 页面路径变化后,自动关闭此modal + */ + useEffect(() => { + setIsModalOpen(false) + }, [router]) + + /** + * 自动聚焦搜索框 + */ useEffect(() => { if (isModalOpen) { setTimeout(() => { @@ -93,9 +131,10 @@ export default function AlgoliaSearchModal({ cRef }) { resetSearch() } }, [isModalOpen]) + /** - * 对外暴露方法 - */ + * 对外暴露方法 + **/ useImperativeHandle(cRef, () => { return { openSearch: () => { @@ -104,7 +143,10 @@ export default function AlgoliaSearchModal({ cRef }) { } }) - const client = algoliasearch(siteConfig('ALGOLIA_APP_ID'), siteConfig('ALGOLIA_SEARCH_ONLY_APP_KEY')) + const client = algoliasearch( + siteConfig('ALGOLIA_APP_ID'), + siteConfig('ALGOLIA_SEARCH_ONLY_APP_KEY') + ) const index = client.initIndex(siteConfig('ALGOLIA_INDEX')) /** @@ -131,7 +173,9 @@ export default function AlgoliaSearchModal({ cRef }) { setTotalHit(nbHits) setSearchResults(hits) setIsLoading(false) - const doms = document.getElementById('search-wrapper').getElementsByClassName('replace') + const doms = document + .getElementById('search-wrapper') + .getElementsByClassName('replace') setTimeout(() => { replaceSearchResult({ @@ -149,33 +193,35 @@ export default function AlgoliaSearchModal({ cRef }) { } // 定义节流函数,确保在用户停止输入一段时间后才会调用处理搜索的方法 - const throttledHandleInputChange = useRef(throttle((query, page = 0) => { - handleSearch(query, page); - }, 1000)); + const throttledHandleInputChange = useRef( + throttle((query, page = 0) => { + handleSearch(query, page) + }, 1000) + ) // 用于存储搜索延迟的计时器 - const searchTimer = useRef(null); + const searchTimer = useRef(null) // 修改input的onChange事件处理函数 - const handleInputChange = (e) => { - const query = e.target.value; + const handleInputChange = e => { + const query = e.target.value // 如果已经有计时器在等待搜索,先清除之前的计时器 if (searchTimer.current) { - clearTimeout(searchTimer.current); + clearTimeout(searchTimer.current) } // 设置新的计时器,在用户停止输入一段时间后触发搜索 searchTimer.current = setTimeout(() => { - throttledHandleInputChange.current(query); - }, 800); - }; + throttledHandleInputChange.current(query) + }, 800) + } /** * 切换页码 * @param {*} page */ - const switchPage = (page) => { + const switchPage = page => { throttledHandleInputChange.current(keyword, page) } @@ -191,58 +237,58 @@ export default function AlgoliaSearchModal({ cRef }) { } return (
+ id='search-wrapper' + className={`${ + isModalOpen ? 'opacity-100' : 'invisible opacity-0 pointer-events-none' + } z-30 fixed h-screen w-screen left-0 top-0 sm:mt-12 flex items-start justify-center mt-0`}> {/* 模态框 */}
-
-
搜索
+ className={`${ + isModalOpen ? 'opacity-100' : 'invisible opacity-0 translate-y-10' + } flex flex-col justify-between w-full min-h-[10rem] h-full md:h-fit max-w-xl dark:bg-hexo-black-gray dark:border-gray-800 bg-white dark:bg- p-5 rounded-lg z-50 shadow border hover:border-blue-600 duration-300 transition-all `}> +
+
+ 搜索 +
+ className='text-gray-600 fa-solid fa-xmark p-1 cursor-pointer hover:text-blue-600' + onClick={closeModal}>
handleInputChange(e)} - className="text-black dark:text-gray-200 bg-gray-50 dark:bg-gray-600 outline-blue-500 w-full px-4 my-2 py-1 mb-4 border rounded-md" + className='text-black dark:text-gray-200 bg-gray-50 dark:bg-gray-600 outline-blue-500 w-full px-4 my-2 py-1 mb-4 border rounded-md' ref={inputRef} /> {/* 标签组 */} -
+
- { - searchResults.length === 0 && keyword && !isLoading && ( -
-

无法找到相关结果 - "{keyword}"

-
- ) - } + {searchResults.length === 0 && keyword && !isLoading && ( +
+

+ {' '} + 无法找到相关结果 + "{keyword}" +

+
+ )}
- {totalHit === 0 && (
- { - ShortCutActions.map((action, index) => { - return
{action.key}
- {action.action}
- }) - } -
) - } + {totalHit === 0 && ( +
+ {ShortCutActions.map((action, index) => { + return ( + +
+ {action.key} +
+ + {action.action} + +
+ ) + })} +
+ )}
{totalHit > 0 && (

@@ -266,19 +319,18 @@ export default function AlgoliaSearchModal({ cRef }) {

)}
-
- - Algolia 提供搜索服务 +
+ + Algolia 提供搜索服务
-
{/* 遮罩 */}
) @@ -292,21 +344,31 @@ function TagGroups() { // 获取tagOptions数组前十个 const firstTenTags = tagOptions?.slice(0, 10) - return
- { - firstTenTags?.map((tag, index) => { - return -
-
{tag.name}
{tag.count ? {tag.count} : <>} -
- - - }) - } -
+ return ( +
+ {firstTenTags?.map((tag, index) => { + return ( + +
+
{tag.name}
+ {tag.count ? ( + {tag.count} + ) : ( + <> + )} +
+ + ) + })} +
+ ) } /** @@ -321,16 +383,16 @@ function Pagination(props) { return (
{Array.from({ length: totalPage }, (_, i) => { - const classNames = page === i - ? 'font-bold text-white bg-blue-600 dark:bg-yellow-600 rounded' - : 'hover:text-blue-600 hover:font-bold dark:text-gray-300' + const classNames = + page === i + ? 'font-bold text-white bg-blue-600 dark:bg-yellow-600 rounded' + : 'hover:text-blue-600 hover:font-bold dark:text-gray-300' return (
switchPage(i)} className={`text-center cursor-pointer w-6 h-6 ${classNames}`} - key={i} - > + key={i}> {i + 1}
)