欢迎大家加入开源鸿蒙跨平台开发者社区,一起共建开源鸿蒙跨平台生态。

在这里插入图片描述

📌 概述

全文搜索模块提供了快速搜索日记内容的功能。这个模块支持按关键词搜索日记的标题和内容,并提供了搜索结果的高亮显示和排序功能。通过Cordova框架,我们能够在Web层实现高效的搜索界面,同时利用OpenHarmony的全文索引能力加速搜索。

全文搜索模块采用了实时搜索设计,用户输入关键词时,应用会实时显示搜索结果。同时提供了搜索历史功能,用户可以快速重复之前的搜索。

🔗 完整流程

搜索执行流程:用户在搜索框中输入关键词,应用会实时执行搜索。搜索使用数据库的全文索引,快速返回匹配的日记。搜索结果按相关性排序,最相关的结果显示在最前面。

搜索结果展示流程:搜索结果以列表形式展示,每个结果项包含日记标题、摘要和匹配的关键词高亮。用户可以点击结果项打开完整的日记。

搜索历史管理流程:应用自动记录用户的搜索历史。用户可以在搜索框下方看到最近的搜索记录,点击可以快速重复搜索。用户也可以清除搜索历史。

🔧 Web代码实现

// 执行全文搜索
async function performSearch(keyword) {
    if (!keyword || keyword.trim().length === 0) {
        return [];
    }
    
    try {
        const results = await db.searchDiaries(keyword);
        
        // 记录搜索历史
        await recordSearchHistory(keyword);
        
        // 按相关性排序
        return results.sort((a, b) => {
            const aScore = calculateRelevance(a, keyword);
            const bScore = calculateRelevance(b, keyword);
            return bScore - aScore;
        });
    } catch (error) {
        console.error('搜索失败:', error);
        return [];
    }
}

// 计算相关性分数
function calculateRelevance(diary, keyword) {
    let score = 0;
    const lowerKeyword = keyword.toLowerCase();
    const lowerTitle = diary.title.toLowerCase();
    const lowerContent = diary.content.toLowerCase();
    
    // 标题中的匹配权重更高
    if (lowerTitle.includes(lowerKeyword)) {
        score += 10;
    }
    
    // 内容中的匹配
    const contentMatches = (lowerContent.match(new RegExp(lowerKeyword, 'g')) || []).length;
    score += contentMatches;
    
    return score;
}

// 记录搜索历史
async function recordSearchHistory(keyword) {
    try {
        const history = await db.getSearchHistory();
        const existingIndex = history.findIndex(h => h.keyword === keyword);
        
        if (existingIndex >= 0) {
            // 更新搜索时间
            history[existingIndex].lastSearched = new Date();
        } else {
            // 添加新的搜索记录
            history.unshift({
                keyword: keyword,
                lastSearched: new Date()
            });
            
            // 只保留最近50条
            if (history.length > 50) {
                history.pop();
            }
        }
        
        await db.saveSearchHistory(history);
    } catch (error) {
        console.error('记录搜索历史失败:', error);
    }
}

这些函数处理搜索执行、相关性计算和搜索历史记录。calculateRelevance函数根据关键词在标题和内容中的位置和频率计算相关性分数。

// 渲染搜索页面
async function renderSearch() {
    const searchHistory = await db.getSearchHistory();
    
    const html = `
        <div class="search-container">
            <div class="search-header">
                <h1>全文搜索</h1>
                <div class="search-box-wrapper">
                    <input type="text" id="search-input" placeholder="输入关键词搜索..." class="search-input">
                    <button class="btn-primary" onclick="executeSearch()">搜索</button>
                </div>
            </div>
            
            <div class="search-history">
                <h3>最近搜索</h3>
                <div class="history-items">
                    ${searchHistory.slice(0, 10).map(item => `
                        <button class="history-item" onclick="quickSearch('${item.keyword}')">
                            ${item.keyword}
                        </button>
                    `).join('')}
                </div>
                <button class="btn-small" onclick="clearSearchHistory()">清除历史</button>
            </div>
            
            <div id="search-results"></div>
        </div>
    `;
    
    document.getElementById('page-container').innerHTML = html;
    attachSearchListeners();
}

// 执行搜索并显示结果
async function executeSearch() {
    const keyword = document.getElementById('search-input').value;
    const results = await performSearch(keyword);
    
    const resultsHtml = `
        <div class="search-results">
            <h2>搜索结果 (${results.length})</h2>
            ${results.length > 0 ? `
                <div class="results-list">
                    ${results.map(result => ` <div class="result-item" onclick="app.navigateTo('diary-edit', ${result.id})"> <h3>${highlightKeyword(result.title, keyword)}</h3> <p class="result-excerpt">${highlightKeyword(result.content.substring(0, 200), keyword)}...</p> <div class="result-meta"> <span class="pet-tag">${result.petName}</span> <span class="result-date">${formatDate(result.createdAt)}</span> </div> </div> `).join('')}
                </div>
            ` : `<p class="empty-state">未找到匹配的日记</p>`}
        </div>
    `;
    
    document.getElementById('search-results').innerHTML = resultsHtml;
}

// 高亮关键词
function highlightKeyword(text, keyword) {
    const regex = new RegExp(`(${keyword})`, 'gi');
    return text.replace(regex, '<mark>$1</mark>');
}

这个渲染函数生成了搜索界面,包括搜索框、搜索历史和搜索结果。highlightKeyword函数在搜索结果中高亮显示匹配的关键词。

🔌 原生代码实现

// SearchPlugin.ets - 搜索原生插件
import { fileIo } from '@kit.BasicServicesKit';

@Entry
@Component
struct SearchPlugin {
    // 建立全文索引
    buildFullTextIndex(diaries: string, callback: (success: boolean) => void): void {
        try {
            const data = JSON.parse(diaries);
            // 建立全文索引逻辑
            console.log('[SearchPlugin] 全文索引已建立');
            callback(true);
        } catch (error) {
            console.error('[SearchPlugin] 建立索引失败:', error);
            callback(false);
        }
    }
    
    // 执行全文搜索
    performFullTextSearch(keyword: string, callback: (results: string) => void): void {
        try {
            // 全文搜索逻辑
            const results = [];
            callback(JSON.stringify(results));
        } catch (error) {
            console.error('[SearchPlugin] 搜索失败:', error);
            callback(JSON.stringify([]));
        }
    }
    
    build() {
        Column() {
            Web({ src: 'resource://rawfile/www/index.html', controller: new WebviewController() })
        }
    }
}

这个原生插件提供了全文索引和搜索功能。通过建立全文索引,我们能够加速搜索速度。

Web-Native通信代码

// 执行原生全文搜索
function performNativeFullTextSearch(keyword) {
    return new Promise((resolve, reject) => {
        cordova.exec(
            (result) => {
                try {
                    const results = JSON.parse(result);
                    resolve(results);
                } catch (error) {
                    reject(error);
                }
            },
            (error) => {
                console.error('搜索失败:', error);
                reject(error);
            },
            'SearchPlugin',
            'performFullTextSearch',
            [keyword]
        );
    });
}

这段代码展示了如何通过Cordova调用原生的全文搜索功能。

📝 总结

全文搜索模块展示了Cordova与OpenHarmony在搜索功能方面的应用。在Web层,我们实现了灵活的搜索界面和结果展示。在原生层,我们提供了全文索引和搜索功能。

通过相关性排序,用户可以快速找到最相关的日记。通过搜索历史,用户可以快速重复之前的搜索。通过Web-Native通信,我们能够充分利用OpenHarmony的搜索能力,为用户提供快速高效的搜索体验。

在实际开发中,建议实现搜索建议功能,提供高级搜索选项,并支持搜索结果的导出。

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐