added 搜索功能

This commit is contained in:
Vaica committed 2026-01-28 23:20:39 +08:00
1 parent 53afae972b
commit 4baf51f4b1
7 files changed
+803 -2

No files matched your search

+241
View File
@@ -461,3 +461,244 @@ function scrollToCommentsAndQuote(text) {
}, 500);
}
}
/* Search Functionality */
function initSearchFunctionality() {
const searchBtn = document.getElementById('search-btn');
const searchModal = document.getElementById('search-modal');
const closeSearch = document.querySelector('.close-search');
const searchInput = document.getElementById('search-input');
const searchResults = document.getElementById('search-results');
const searchSubmit = document.getElementById('search-submit');
// Global variables (window scope) to persist across re-inits if needed,
// but better to keep them scoped if we re-fetch.
// For simplicity, we keep index loading check.
if (!window.searchIndex) window.searchIndex = [];
if (!window.isIndexLoaded) window.isIndexLoaded = false;
if (!searchBtn || !searchModal) return;
// Open Modal
// Use named function to avoid duplicate listeners if we didn't clean up (though init is usually called once per page load/pjax)
function openModal() {
searchModal.classList.add('show');
if (!window.isIndexLoaded) {
loadSearchIndex();
}
setTimeout(() => searchInput.focus(), 100);
}
searchBtn.removeEventListener('click', openModal); // Prevent duplicates
searchBtn.addEventListener('click', openModal);
// Close Modal
function closeModal() {
searchModal.classList.remove('show');
}
if (closeSearch) {
closeSearch.onclick = closeModal;
}
// Close when clicking outside
window.onclick = function(e) {
if (e.target === searchModal) {
closeModal();
}
};
// Close on Escape key
document.onkeydown = function(e) {
if (e.key === 'Escape' && searchModal.classList.contains('show')) {
closeModal();
}
};
// Load Index
function loadSearchIndex() {
fetch('/index.json')
.then(response => response.json())
.then(data => {
window.searchIndex = data;
window.isIndexLoaded = true;
})
.catch(error => {
console.error('Error loading search index:', error);
if(searchResults) searchResults.innerHTML = '<p class="search-tip">搜索索引加载失败</p>';
});
}
// Perform Search
function performSearch() {
if(!searchInput) return;
const query = searchInput.value.trim().toLowerCase();
if (query === '') {
searchResults.innerHTML = '<p class="search-tip">输入关键词并回车进行搜索</p>';
return;
}
if (!window.isIndexLoaded) {
searchResults.innerHTML = '<p class="search-tip">正在加载索引...</p>';
// Retry after a short delay if index is loading
setTimeout(performSearch, 500);
return;
}
const results = window.searchIndex.filter(item => {
const title = item.title ? item.title.toLowerCase() : '';
const summary = item.summary ? item.summary.toLowerCase() : '';
return title.includes(query) || summary.includes(query);
});
displayResults(results);
}
// Display Results
function displayResults(results) {
if (results.length === 0) {
searchResults.innerHTML = '<p class="search-tip">未找到相关文章</p>';
return;
}
let html = '';
results.forEach(item => {
html += `
<a href="${item.permalink}" class="search-result-item" style="text-decoration:none; display:block; color:inherit;">
<span class="search-result-title" style="display:block;font-weight:600;margin-bottom:5px;">${item.title}</span>
<span class="search-result-date" style="font-size:12px;color:#999;display:block;margin-bottom:5px;">${item.date}</span>
<div class="search-result-summary">${item.summary}</div>
</a>
`;
});
searchResults.innerHTML = html;
if (window.pjax) window.pjax.refresh(searchResults);
// Add click listener to close modal on result click
const resultLinks = searchResults.querySelectorAll('.search-result-item');
resultLinks.forEach(link => {
link.addEventListener('click', function() {
closeModal();
});
});
}
// Event Listeners for Search
if (searchSubmit) {
searchSubmit.onclick = performSearch;
}
if (searchInput) {
searchInput.onkeypress = function(e) {
if (e.key === 'Enter') {
performSearch();
}
};
// Optional: Live search with debounce
let debounceTimer;
searchInput.oninput = function() {
clearTimeout(debounceTimer);
debounceTimer = setTimeout(performSearch, 300);
};
}
/* Inline Search Logic */
const essayHeader = document.getElementById('essay-header');
const searchContainer = document.getElementById('search-container');
const inlineSearchInput = document.getElementById('inline-search-input');
const inlineSearchResults = document.getElementById('inline-search-results');
if (essayHeader && searchContainer && inlineSearchInput) {
window.toggleSearchMode = function(show) {
if (show) {
essayHeader.style.display = 'none';
searchContainer.style.display = 'block';
inlineSearchInput.focus();
if (!window.isIndexLoaded) {
loadSearchIndex();
}
} else {
essayHeader.style.display = 'block';
searchContainer.style.display = 'none';
inlineSearchInput.value = '';
inlineSearchResults.style.display = 'none';
}
};
// Close when clicking outside - delegated to document body to handle pjax updates
document.body.onclick = function(e) {
const isClickInside = essayHeader.contains(e.target) ||
searchContainer.contains(e.target) ||
inlineSearchResults.contains(e.target);
if (!isClickInside && searchContainer.style.display === 'block') {
window.toggleSearchMode(false);
}
// Also handle modal outside click here if needed, but window.onclick handles that
if (e.target === searchModal) {
closeModal();
}
};
// Inline Search Function
function performInlineSearch() {
const query = inlineSearchInput.value.trim().toLowerCase();
if (query === '') {
inlineSearchResults.style.display = 'none';
return;
}
if (!window.isIndexLoaded) {
// Wait if loading
setTimeout(performInlineSearch, 500);
return;
}
const results = window.searchIndex.filter(item => {
const title = item.title ? item.title.toLowerCase() : '';
const summary = item.summary ? item.summary.toLowerCase() : '';
return title.includes(query) || summary.includes(query);
});
displayInlineResults(results);
}
function displayInlineResults(results) {
if (results.length === 0) {
inlineSearchResults.innerHTML = '<div class="search-result-item" style="text-align:center;color:#999;">未找到相关文章</div>';
inlineSearchResults.style.display = 'block';
return;
}
let html = '';
results.slice(0, 5).forEach(item => { // Limit to 5 inline results
html += `
<a href="${item.permalink}" class="search-result-item">
<span class="search-result-title">${item.title}</span>
<div class="search-result-summary">${item.summary}</div>
</a>
`;
});
inlineSearchResults.innerHTML = html;
inlineSearchResults.style.display = 'block';
if (window.pjax) window.pjax.refresh(inlineSearchResults);
}
let inlineDebounce;
inlineSearchInput.oninput = function() {
clearTimeout(inlineDebounce);
inlineDebounce = setTimeout(performInlineSearch, 300);
};
// Handle Escape key
inlineSearchInput.onkeydown = function(e) {
if (e.key === 'Escape') {
window.toggleSearchMode(false);
}
};
}
}
document.addEventListener('DOMContentLoaded', initSearchFunctionality);
// Re-init on Pjax complete
document.addEventListener('pjax:complete', initSearchFunctionality);