From 05fbd60c064d3d6109c2bc075a847195b23130bf Mon Sep 17 00:00:00 2001 From: Leo Yihao Qin Date: Thu, 21 Nov 2024 23:50:00 +0800 Subject: [PATCH] feat: replace search.js with fuse search Added fuse.js for fuzzy search and added the search.json example format to the doc\features\search.md --- docs/features/search.md | 19 +++++- layout/_partial/head.ejs | 5 ++ source/js/search.js | 134 +++++++++++++++++++++------------------ 3 files changed, 95 insertions(+), 63 deletions(-) diff --git a/docs/features/search.md b/docs/features/search.md index 9197fce..45263e0 100644 --- a/docs/features/search.md +++ b/docs/features/search.md @@ -13,11 +13,26 @@ Search features are enabled by default, but requires a few steps to make it avai path: search.json content: false ``` -3. Add new search page so that Hexo will generate it. +3. Add the search.json file to blog root directory, the following is an example: + ```json + [ + { + "url": "/articles/Article-1-Title", + "title": "Article-1-Title", + "tags": ["tag1", "tag2"] + }, + { + "url": "/articles/Article-2-Title", + "title": "Article-2-Title", + "tags": ["tag1", "tag2"] + }, + ] + ``` +4. Add new search page so that Hexo will generate it. ```sh $ hexo new page 'search' ``` -4. Replace all its content with: +1. Replace all its content with: ```markdown --- type: search diff --git a/layout/_partial/head.ejs b/layout/_partial/head.ejs index 546cddd..88e31d6 100644 --- a/layout/_partial/head.ejs +++ b/layout/_partial/head.ejs @@ -111,4 +111,9 @@ href="https://unpkg.com/@waline/client@v2/dist/waline.css" /> <% } %> + + <% if (theme.search == true && page.type == 'search') { %> + + <% } %> + \ No newline at end of file diff --git a/source/js/search.js b/source/js/search.js index 5cb95ac..57eae3d 100644 --- a/source/js/search.js +++ b/source/js/search.js @@ -1,74 +1,86 @@ -(() => { +;(() => { var searchIndex = [] const searchForm = document.getElementById('search-form') const searchBox = document.getElementById('searchbox') const searchResults = document.getElementById('search-results') - + searchBox.select() - - const doSearch = (keyword) => { - var results = [] - var resultsEl = [] - - for (let i = 0; i < searchIndex.length; i++) { - const currentItem = searchIndex[i]; - - if (JSON.stringify(currentItem).search(keyword) !== -1) { - results.push(currentItem) - } - } - - if (results.length > 0) { - for (let i = 0; i < results.length; i++) { - const currentResult = results[i]; - const currentResultEl = document.createElement('article') - currentResultEl.classList.add('post-list-item') - currentResultEl.innerHTML = ` - + + const doSearch = keyword => { + var results = [] + var resultsEl = [] + + const options = { + keys: ['title', 'tags', 'categories'], + caseSensitive: false, + threshold: 0.3 + }; + + const fuse = new Fuse(searchIndex, options); + results = fuse.search(keyword).map(result => result.item) + console.log(searchIndex) + + if (results.length > 0) { + for (let i = 0; i < results.length; i++) { + const currentResult = results[i] + const currentResultEl = document.createElement('article') + currentResultEl.classList.add('post-list-item') + currentResultEl.innerHTML = ` +
- ${(() => { - if (currentResult.categories) { - return `
${(() => { - let categories = '' - for (let i = 0; i < currentResult.categories.length; i++) { - const currentCategory = currentResult.categories[i] - categories += `${currentCategory}` - } - return categories - })()}
` - } else { - return '' - } - })()} -
${currentResult.title}
-
-
- ` - resultsEl.push(currentResultEl) + ${(() => { + if (currentResult.categories && Array.isArray(currentResult.categories)) { + return `
${(() => { + let categories = '' + for (let i = 0; i < currentResult.categories.length; i++) { + const currentCategory = currentResult.categories[i] + categories += `${currentCategory}` } + return categories + })()}
` } else { - const el = document.createElement('div') - el.className = 'no-results' - el.innerHTML = 'No results found.' - resultsEl.push(el) + return '' } - - searchResults.innerHTML = '' - for (let i = 0; i < resultsEl.length; i++) { - const element = resultsEl[i]; - searchResults.appendChild(element) + })()} +
${currentResult.title}
+ + + ` + resultsEl.push(currentResultEl) } + } else { + const el = document.createElement('div') + el.className = 'no-results' + el.innerHTML = 'No results found.' + resultsEl.push(el) + } + + searchResults.innerHTML = '' + for (let i = 0; i < resultsEl.length; i++) { + const element = resultsEl[i] + searchResults.appendChild(element) + } } - - searchForm.addEventListener('submit', (ev) => { - ev.preventDefault() - if (searchIndex != '') { + + searchForm.addEventListener('submit', ev => { + ev.preventDefault() + if (searchIndex.length > 0) { + doSearch(searchBox.value) + } else { + fetch( + document.body.attributes['data-config-root'].value + + document.body.attributes['data-search-path'].value, + ) + .then(res => res.json()) + .then(data => { + searchIndex = data doSearch(searchBox.value) - } else { - fetch(document.body.attributes['data-config-root'].value + document.body.attributes['data-search-path'].value).then(res => res.json()).then(data => { - searchIndex = data - doSearch(searchBox.value) - }) - } + }) + } }) -})() \ No newline at end of file + })() + \ No newline at end of file