在昨天的文章中,我們成功為 GASO 添加了美麗的世界地圖背景,讓視覺效果更加豐富。今天我們要解決一個實際的使用者痛點:當節點數量很多時,使用者很難快速找到想要的節點。
因此,我們決定為 GASO 添加一個智能搜尋功能,讓使用者可以透過輸入關鍵字來快速找到並選擇節點,大幅提升使用體驗。
首先,我們在頁面頂部添加了搜尋功能的基本結構:
<!-- 搜尋功能 -->
<div class="search-container">
<div class="search-box">
<input type="text" id="searchInput" placeholder="搜尋節點..." autocomplete="off" />
<div id="searchResults" class="search-results"></div>
</div>
</div>
設計考量:
autocomplete="off"
避免瀏覽器自動完成干擾為了提供良好的視覺體驗,我們設計了現代化的搜尋介面樣式:
/* 搜尋功能樣式 */
.search-container {
margin: 1rem 0;
position: relative;
}
.search-box {
position: relative;
max-width: 400px;
}
#searchInput {
width: 100%;
padding: 12px 16px;
border: 2px solid #ddd;
border-radius: 8px;
font-size: 16px;
box-sizing: border-box;
transition: border-color 0.3s ease;
}
#searchInput:focus {
outline: none;
border-color: #007bff;
box-shadow: 0 0 0 3px rgba(0, 123, 255, 0.1);
}
.search-results {
position: absolute;
top: 100%;
left: 0;
right: 0;
background: white;
border: 1px solid #ddd;
border-top: none;
border-radius: 0 0 8px 8px;
max-height: 300px;
overflow-y: auto;
z-index: 1000;
display: none;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
}
樣式特色:
接下來實現核心的搜尋功能:
// 搜尋節點
function searchNodes(keyword) {
if (!keyword || keyword.length < 1) {
searchResults.classList.remove('show');
return;
}
const results = state.nodeDetails.filter(node => {
const searchText = `${node.label} ${node.prompt} ${node.attribute}`.toLowerCase();
return searchText.includes(keyword.toLowerCase());
});
displaySearchResults(results, keyword);
}
// 顯示搜尋結果
function displaySearchResults(results, keyword) {
if (results.length === 0) {
searchResults.innerHTML = '<div class="no-results">找不到符合條件的節點</div>';
} else {
searchResults.innerHTML = results.map(node => `
<div class="search-result-item" data-node-id="${node.id}">
<div class="search-result-title">${highlightText(node.label, keyword)}</div>
<div class="search-result-subtitle">${highlightText(node.prompt.substring(0, 100) + (node.prompt.length > 100 ? '...' : ''), keyword)}</div>
</div>
`).join('');
}
searchResults.classList.add('show');
}
搜尋特色:
為了讓搜尋結果更直觀,我們實現了關鍵字高亮功能:
// 高亮搜尋關鍵字
function highlightText(text, keyword) {
if (!keyword) return text;
const regex = new RegExp(`(${keyword})`, 'gi');
return text.replace(regex, '<span class="search-result-highlight">$1</span>');
}
高亮效果:
gi
標誌)最關鍵的部分是讓搜尋結果的點擊能夠觸發節點點擊效果:
// 處理搜尋結果點擊
function handleSearchResultClick(nodeId) {
// 通過節點標籤找到對應的 SVG 節點
const nodeDetail = state.nodeDetails.find(n => n.id === nodeId);
if (!nodeDetail) return;
// 通過標籤文字找到對應的 SVG 節點
const allNodes = svg.querySelectorAll('g.node');
let nodeElement = null;
for (const node of allNodes) {
const textElement = node.querySelector('text');
if (textElement && textElement.textContent === nodeDetail.label) {
nodeElement = node;
break;
}
}
if (nodeElement) {
// 模擬節點點擊事件
const clickEvent = new MouseEvent('click', {
bubbles: true,
cancelable: true,
view: window
});
nodeElement.dispatchEvent(clickEvent);
}
}
技術要點:
MouseEvent
模擬真實點擊事件在開發過程中,我們遇到了一個重要的技術難題:
問題: 搜尋結果點擊後只顯示節點資訊,但沒有高亮路徑
原因分析:
SL1
node45
解決方案:
改變查找邏輯,通過節點標籤文字來匹配:
// 通過標籤文字找到對應的 SVG 節點
const allNodes = svg.querySelectorAll('g.node');
let nodeElement = null;
for (const node of allNodes) {
const textElement = node.querySelector('text');
if (textElement && textElement.textContent === nodeDetail.label) {
nodeElement = node;
break;
}
}
最後,我們添加了一些細節來提升使用者體驗:
// 搜尋輸入事件監聽
if (searchInput) {
let searchTimeout;
searchInput.addEventListener('input', function(e) {
clearTimeout(searchTimeout);
searchTimeout = setTimeout(() => {
searchNodes(e.target.value);
}, 150); // 150ms 延遲,避免過於頻繁的搜尋
});
// 點擊外部關閉搜尋結果
document.addEventListener('click', function(e) {
if (!searchInput.contains(e.target) && !searchResults.contains(e.target)) {
searchResults.classList.remove('show');
}
});
}
體驗優化:
MouseEvent
模擬真實點擊經過今天的開發,GASO 現在具備了:
搜尋範例:
操作流程:
明天我們將繼續優化 GASO 的功能,可能的方向包括:
今天的開發重點在於解決實際的使用者痛點:在節點數量眾多的情況下,如何快速找到想要的節點。通過實現智能搜尋功能,我們大幅提升了 GASO 的使用體驗。
這個功能看似簡單,但實際上涉及了:
這些技術要點都是前端開發中常見但重要的技能,對於提升應用程式的可用性至關重要。
如果想要看一些我的鐵人賽花邊心得,
也歡迎追蹤我的 Threads 和 Facebook