鸿蒙掌上驾考宝典应用开发47: 搜索组件——考题搜索功能实现
2026/8/18 17:36:56 网站建设 项目流程

第47篇:搜索组件——考题搜索功能实现

一、引言

搜索功能是驾考应用中帮助用户快速定位特定考题的重要工具。当用户遇到不会的题目想查找相关知识点,或者想针对某个特定主题进行练习时,搜索功能就派上了用场。DriverLicenseExam 项目的search组件封装了搜索入口、搜索控制器和搜索结果跳转的完整流程。本文将深入解析其实现。

二、搜索组件结构

2.1 组件目录

search/ ├──src/main/ets/ │ ├── components/ │ │ └── SearchComponents.ets← 搜索 UI 组件 │ └── controller/ │ └── SearchController.ets← 搜索控制器 └── Index.ets← 模块导出

2.2 搜索流程

用户点击搜索框 │ ▼ 进入 SearchPage │ ▼ 输入关键词 │ ▼ SearchController.search(keyword) │ ▼ 在 ExamDetail 中匹配题目文本 │ ├── 匹配成功 → 跳转到练习页,展示搜索结果 │ └── 匹配失败 → 显示"未找到相关题目"提示

三、搜索入口实现

3.1 主页面搜索框

搜索入口位于 HomeView 顶部,与城市选择并列:

// HomeView.ets - 顶部搜索框Row(){// 城市选择Row(){Text(this.guideService.getGuideData().city) .fontSize(14).fontColor($r('sys.color.font_primary')) .fontWeight(FontWeight.Medium).margin({ right:4}) .maxFontScale(1);Image($r('app.media.city_triangle')) .width(12).height(12); } .onClick(()=> { this.vm.navStack.pushPathByName('selectCityView',true); }) .margin({ left:12, right:8});// 搜索框Row({space: 8 }){Image($r('app.media.ic_glass')) .width(16) .fillColor($r('sys.color.icon_primary'));Text('请输入关键字搜索').fontSize(14).fontColor($r('sys.color.font_secondary')) .maxFontScale(1); } .backgroundColor($r('app.color.search_background')) .height(40) .layoutWeight(1).margin({ right:12}) .padding(12) .borderRadius(8).onClick(()=> { this.vm.navStack.pushPathByName('SearchPage',undefined); }); }

这个搜索框的 UI 设计有几个值得注意的点:

  • 搜索图标:使用$r('app.media.ic_glass')引用本地资源
  • 占位文本:使用Text组件而非TextInput的 placeholder,因为搜索框实际上是点击跳转的入口
  • **layoutWeight(1)**:搜索框占据城市选择后的剩余空间
  • **maxFontScale(1)**:限制搜索框文字不跟随系统字体缩放

3.2 搜索页面

// SearchPage.ets@ComponentV2export struct SearchPage {@Localkeyword: string ='';@LocalsearchResults: ExamDetail[] = [];privatesearchController: SearchController = new SearchController(); build() { NavDestination() { Column() {// 搜索输入框TextInput({ placeholder:'输入考题关键词...', text:this.keyword }) .height(48) .padding({ left:16}) .borderRadius(24) .backgroundColor($r('sys.color.comp_background_primary')) .onChange((value: string) => {this.keyword = value;this.performSearch(); });// 搜索结果列表if(this.searchResults.length >0) { List() { ForEach(this.searchResults, (item: ExamDetail) => { ListItem() {this.searchResultItem(item); } }); } .layoutWeight(1); }else{// 空状态Column() { Image($r('app.media.ic_search_empty')).width(80).height(80); Text('未找到相关题目').fontSize(14).fontColor('#999'); } .layoutWeight(1) .justifyContent(FlexAlign.Center); } } .padding(16); } .title('搜索考题'); } performSearch() {if(this.keyword.trim().length ===0) {this.searchResults = [];return; }// 通过 SearchController 执行搜索this.searchResults =this.searchController.search(this.keyword); } }

四、搜索控制器实现

4.1 SearchController

// SearchController.etsexportclassSearchController{privateexamDetails:ExamDetail[] = [];constructor() {// 初始化时获取所有考题数据this.examDetails=ExamService.instance(null).getAllExamDetails(); }search(keyword:string):ExamDetail[] {if(!keyword || keyword.trim().length===0) {return[]; }constlowerKeyword = keyword.toLowerCase();// 在题目文本和章节名称中匹配returnthis.examDetails.filter(item=>item.question.toLowerCase().includes(lowerKeyword) || item.chapterName.toLowerCase().includes(lowerKeyword) ); }// 按题型筛选搜索结果searchByType(keyword:string,type:QuestionTypeEnum):ExamDetail[] {constresults =this.search(keyword);returnresults.filter(item=>item.questionType===type); } }

4.2 搜索结果的跳转

搜索结果的点击跳转到练习页面,使用EXAM_MANAGER_TYPE.search类型:

// 搜索项点击事件@Builder searchResultItem(item: ExamDetail){Row(){Column({space: 4 }){Text(item.question).fontSize(14).maxLines(2).textOverflow({overflow: TextOverflow.Ellipsis });Text(item.chapterName).fontSize(12).fontColor('#999'); } .layoutWeight(1); } .padding(12) .width('100%') .onClick(()=> { const param: ROUTE_PARAM = { title: '搜索结果',type:EXAM_MANAGER_TYPE.search, keyword: this.keyword, }; this.vm.navStack.pushPathByName('practiceView',param); }); }

五、搜索数据流

5.1 搜索与 ExamService 的集成

搜索功能与 ExamService 的getExamQuestionList方法集成:

// ExamService.ets - 搜索数据过滤case EXAM_MANAGER_TYPE.search: examData = originData.filter(item=>item.question.includes(searchCondition));break;

5.2 搜索参数传递

// 搜索跳转时传递 keyword 参数constparam: ROUTE_PARAM = { title:'搜索结果', type: EXAM_MANAGER_TYPE.search, keyword:'交通标志',// 搜索关键词};// PracticeView 接收参数.onReady((ctx: NavDestinationContext) => {constparam =this.vm.navStack.getParamByIndex(index -1)asROUTE_PARAM;if(param.keyword) {this.keyword = param.keyword; }this.getExamManger(); });

六、搜索功能优化

6.1 防抖处理

为了避免用户每次输入都触发搜索,可以添加防抖机制:

privatesearchTimer: number = -1; performSearch() {if(this.searchTimer !== -1) { clearTimeout(this.searchTimer); }this.searchTimer = setTimeout(() => {if(this.keyword.trim().length ===0) {this.searchResults = [];return; }this.searchResults =this.searchController.search(this.keyword); },300);// 300ms 防抖}

6.2 搜索历史

可以扩展搜索功能,记录用户的历史搜索关键词(通过 Preferences 持久化):

saveSearchHistory(keyword:string){ const preferencesUtil =PreferencesUtil.getInstance(); const preference = preferencesUtil.getPreferences(context);lethistory = preferencesUtil.getPreferencesValue(preference, 'searchHistory')asstring[];if(!history) history =[];if(!history.includes(keyword)) { history.unshift(keyword);if(history.length >10) history.pop();// 只保留最近10条preferencesUtil.preferencesPut(preference, 'searchHistory',history); } }

七、总结

搜索组件通过 SearchController 和 SearchComponents 的组合,实现了完整的搜索功能:

  1. 搜索入口:主页面的搜索框,点击跳转到搜索页面
  2. 搜索逻辑:关键词匹配题目文本和章节名称
  3. 结果展示:列表展示搜索结果,支持点击跳转
  4. 数据集成:与 ExamService 的 EXAM_MANAGER_TYPE.search 集成
  5. 扩展性:支持防抖、搜索历史等优化

关键源码文件:

  • components/search/src/main/ets/components/SearchComponents.ets— 搜索组件
  • components/search/src/main/ets/controller/SearchController.ets— 搜索控制器
  • products/entry/src/main/ets/pages/home/HomeView.ets— 搜索入口
  • products/entry/src/main/ets/pages/home/SearchPage.ets— 搜索页面
  • commons/datasource/src/main/ets/ExamService.ets— 搜索数据源

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询