Skip to content

Commit 7fdd721

Browse files
committed
修复搜索功能:添加Fuse.js库支持并修复路径问题
1 parent cf074b0 commit 7fdd721

2 files changed

Lines changed: 181 additions & 16 deletions

File tree

assets/js/fastsearch.js

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
import * as params from '@params';
2+
3+
let fuse; // holds our search engine
4+
let resList = document.getElementById('searchResults');
5+
let sInput = document.getElementById('searchInput');
6+
let first, last, current_elem = null
7+
let resultsAvailable = false;
8+
9+
// load our search index
10+
window.onload = function () {
11+
let xhr = new XMLHttpRequest();
12+
xhr.onreadystatechange = function () {
13+
if (xhr.readyState === 4) {
14+
if (xhr.status === 200) {
15+
let data = JSON.parse(xhr.responseText);
16+
if (data) {
17+
// fuse.js options; check fuse.js website for details
18+
let options = {
19+
distance: 100,
20+
threshold: 0.4,
21+
ignoreLocation: true,
22+
keys: [
23+
'title',
24+
'permalink',
25+
'summary',
26+
'content'
27+
]
28+
};
29+
if (params.fuseOpts) {
30+
options = {
31+
isCaseSensitive: params.fuseOpts.iscasesensitive ?? false,
32+
includeScore: params.fuseOpts.includescore ?? false,
33+
includeMatches: params.fuseOpts.includematches ?? false,
34+
minMatchCharLength: params.fuseOpts.minmatchcharlength ?? 1,
35+
shouldSort: params.fuseOpts.shouldsort ?? true,
36+
findAllMatches: params.fuseOpts.findallmatches ?? false,
37+
keys: params.fuseOpts.keys ?? ['title', 'permalink', 'summary', 'content'],
38+
location: params.fuseOpts.location ?? 0,
39+
threshold: params.fuseOpts.threshold ?? 0.4,
40+
distance: params.fuseOpts.distance ?? 100,
41+
ignoreLocation: params.fuseOpts.ignorelocation ?? true
42+
}
43+
}
44+
fuse = new Fuse(data, options); // build the index from the json file
45+
}
46+
} else {
47+
console.log(xhr.responseText);
48+
}
49+
}
50+
};
51+
// 使用绝对路径而不是相对路径,确保在所有页面路径下都能正确加载
52+
xhr.open('GET', "/index.json");
53+
xhr.send();
54+
}
55+
56+
function activeToggle(ae) {
57+
document.querySelectorAll('.focus').forEach(function (element) {
58+
// rm focus class
59+
element.classList.remove("focus")
60+
});
61+
if (ae) {
62+
ae.focus()
63+
document.activeElement = current_elem = ae;
64+
ae.parentElement.classList.add("focus")
65+
} else {
66+
document.activeElement.parentElement.classList.add("focus")
67+
}
68+
}
69+
70+
function reset() {
71+
resultsAvailable = false;
72+
resList.innerHTML = sInput.value = ''; // clear inputbox and searchResults
73+
sInput.focus(); // shift focus to input box
74+
}
75+
76+
// execute search as each character is typed
77+
sInput.onkeyup = function (e) {
78+
// run a search query (for "term") every time a letter is typed
79+
// in the search box
80+
if (fuse) {
81+
let results;
82+
if (params.fuseOpts) {
83+
results = fuse.search(this.value.trim(), {limit: params.fuseOpts.limit}); // the actual query being run using fuse.js along with options
84+
} else {
85+
results = fuse.search(this.value.trim()); // the actual query being run using fuse.js
86+
}
87+
if (results.length !== 0) {
88+
// build our html if result exists
89+
let resultSet = ''; // our results bucket
90+
91+
for (let item in results) {
92+
resultSet += `<li class="post-entry"><header class="entry-header">${results[item].item.title}&nbsp;»</header>` +
93+
`<a href="${results[item].item.permalink}" aria-label="${results[item].item.title}"></a></li>`
94+
}
95+
96+
resList.innerHTML = resultSet;
97+
resultsAvailable = true;
98+
first = resList.firstChild;
99+
last = resList.lastChild;
100+
} else {
101+
resultsAvailable = false;
102+
resList.innerHTML = '';
103+
}
104+
}
105+
}
106+
107+
sInput.addEventListener('search', function (e) {
108+
// clicked on x
109+
if (!this.value) reset()
110+
})
111+
112+
// kb bindings
113+
document.onkeydown = function (e) {
114+
let key = e.key;
115+
let ae = document.activeElement;
116+
117+
let inbox = document.getElementById("searchbox").contains(ae)
118+
119+
if (ae === sInput) {
120+
let elements = document.getElementsByClassName('focus');
121+
while (elements.length > 0) {
122+
elements[0].classList.remove('focus');
123+
}
124+
} else if (current_elem) ae = current_elem;
125+
126+
if (key === "Escape") {
127+
reset()
128+
} else if (!resultsAvailable || !inbox) {
129+
return
130+
} else if (key === "ArrowDown") {
131+
e.preventDefault();
132+
if (ae == sInput) {
133+
// if the currently focused element is the search input, focus the <a> of first <li>
134+
activeToggle(resList.firstChild.lastChild);
135+
} else if (ae.parentElement != last) {
136+
// if the currently focused element's parent is last, do nothing
137+
// otherwise select the next search result
138+
activeToggle(ae.parentElement.nextSibling.lastChild);
139+
}
140+
} else if (key === "ArrowUp") {
141+
e.preventDefault();
142+
if (ae.parentElement == first) {
143+
// if the currently focused element is first item, go to input box
144+
activeToggle(sInput);
145+
} else if (ae != sInput) {
146+
// if the currently focused element is input box, do nothing
147+
// otherwise select the previous search result
148+
activeToggle(ae.parentElement.previousSibling.lastChild);
149+
}
150+
} else if (key === "ArrowRight") {
151+
ae.click(); // click on active link
152+
}
153+
}
154+

layouts/partials/header.html

Lines changed: 27 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,15 @@ <h1 class="site-title-text">{{ .Site.Title }}</h1>
2626
</nav>
2727
</header>
2828

29+
<script src="https://cdn.jsdelivr.net/npm/fuse.js@6.6.2"></script>
2930
<script>
3031
(async function () {
32+
// 确保Fuse.js已加载
33+
if (typeof Fuse === 'undefined') {
34+
console.error('Fuse.js library not loaded');
35+
return;
36+
}
37+
3138
try {
3239
const res = await fetch('/index.json');
3340
if (!res.ok) throw new Error('Failed to fetch search index');
@@ -36,6 +43,11 @@ <h1 class="site-title-text">{{ .Site.Title }}</h1>
3643
const input = document.getElementById('headerSearch');
3744
const results = document.getElementById('headerSearchResults');
3845

46+
if (!input || !results) {
47+
console.error('Search elements not found');
48+
return;
49+
}
50+
3951
const fuse = new Fuse(data, {
4052
keys: ['title', 'content', 'description', 'tags', 'categories'],
4153
threshold: 0.3,
@@ -202,21 +214,20 @@ <h3>${item.title}</h3>
202214
}
203215

204216
/* 滚动检测脚本 */
205-
<script>
206-
document.addEventListener('DOMContentLoaded', function() {
207-
const navbar = document.querySelector('.navbar-glass');
208-
209-
function updateNavbar() {
210-
if (window.scrollY > 100) {
211-
navbar.classList.add('scrolled');
212-
} else {
213-
navbar.classList.remove('scrolled');
214-
}
217+
</style>
218+
<script>
219+
document.addEventListener('DOMContentLoaded', function() {
220+
const navbar = document.querySelector('.navbar-glass');
221+
222+
function updateNavbar() {
223+
if (window.scrollY > 100) {
224+
navbar.classList.add('scrolled');
225+
} else {
226+
navbar.classList.remove('scrolled');
215227
}
228+
}
216229

217-
window.addEventListener('scroll', updateNavbar);
218-
updateNavbar(); // 初始化检查
219-
});
220-
</script>
221-
</style>
222-
</style>
230+
window.addEventListener('scroll', updateNavbar);
231+
updateNavbar(); // 初始化检查
232+
});
233+
</script>

0 commit comments

Comments
 (0)