当前位置: 首页 > news >正文

鸿蒙原生应用实战(三):表单交互与搜索筛选——添加包裹、搜索过滤与公司管理

鸿蒙原生应用实战(三):表单交互与搜索筛选——添加包裹、搜索过滤与公司管理

本文是系列第三篇,深入讲解快递追踪 App 中的三个交互型页面:添加包裹表单、搜索与筛选、快递公司管理。涵盖表单验证、选择器实现、多条件搜索、Toggle 开关等实战内容。


一、概述

本项目的交互型页面有三个,各有特点:

页面核心交互技术要点
AddPackagePage文本输入 + 下拉选择 + 表单验证TextInput、自定义Picker、实时校验
SearchPage文本搜索 + 标签筛选 + 结果列表多条件组合查询、Tab 筛选
CompanyManagePage搜索过滤 + Toggle 开关 + 收藏管理计算属性、ToggleType.Switch

二、添加包裹页面(AddPackagePage)

2.1 页面布局

┌─────────────────────────────┐ │ ← 添加包裹 │ ├─────────────────────────────┤ │ 输入快递单号 │ │ ┌───────────────────────┐ │ │ │ 请输入快递单号 │ │ │ └───────────────────────┘ │ │ │ │ 快递公司 │ │ ┌───────────────────────┐ │ │ │ 顺丰速运 ▼ │ │ │ ├───────────────────────┤ │ ← 点击展开 │ │ 圆通速递 │ │ │ │ 中通快递 │ │ │ │ ... │ │ │ └───────────────────────┘ │ │ │ │ 备注 │ │ ┌───────────────────────┐ │ │ │ 选填 │ │ │ └───────────────────────┘ │ │ │ │ ┌───────────────────────┐ │ │ │ 保存 │ │ │ └───────────────────────┘ │ │ 单号格式正确 ✓ │ ← 实时校验提示 └─────────────────────────────┘

2.2 状态管理

@Entry@Componentstruct AddPackagePage{@StatetrackingNo:string='';// 快递单号@StateselectedCompany:string='顺丰速运';// 选中的快递公司@Statenote:string='';// 备注@StateshowPicker:boolean=false;// 选择器展开/收起}

2.3 自定义下拉选择器

鸿蒙没有原生的下拉选择器(Picker/Select),我们用 Text + 条件渲染实现一个:

// 快递公司列表letcourierCompanies:string[]=['顺丰速运','圆通速递','中通快递','韵达快递','京东快递','邮政EMS','极兔速递'];// 选择器触发器Row(){Text(this.selectedCompany)Blank()Text('▼')// 下拉箭头}.onClick(()=>{this.showPicker=!this.showPicker;// 切换展开/收起})// 下拉列表(条件渲染)if(this.showPicker){Column(){ForEach(courierCompanies,(company:string)=>{Text(company).onClick(()=>{this.selectedCompany=company;// 选中this.showPicker=false;// 收起})},(company:string)=>company)}}

设计要点

  • 选中项高亮显示:fontColor(this.selectedCompany === company ? primary : text_primary)
  • 点击列表项后自动收起选择器
  • 列表外部没有点击遮罩层——可以通过再次点击触发器收起

2.4 表单实时验证

// 保存按钮Button($r('app.string.btn_save')).onClick(()=>{if(this.trackingNo.length===0){return;// 空单号不处理}if(this.trackingNo.length<6){return;// 单号太短}router.back();// 验证通过,返回首页})// 实时提示文字Row(){if(this.trackingNo.length>0&&this.trackingNo.length<6){Text('单号长度不足,请检查').fontColor($r('app.color.status_exception'))// 红色警告}elseif(this.trackingNo.length===0){Text('请输入快递单号').fontColor($r('app.color.text_hint'))// 灰色提示}else{Text('单号格式正确 ✓').fontColor($r('app.color.status_delivered'))// 绿色成功}}

三种状态提示

状态条件颜色文案
未输入length === 0灰色请输入快递单号
输入中但不足length > 0 && length < 6红色单号长度不足
输入完成length >= 6绿色单号格式正确 ✓

这是典型的正向反馈设计——用户每输入一个字符都能看到状态变化。

2.5 为什么不使用 TextArea 做备注?

当前备注使用了单行TextInput,对于简短备注(如"手机"“书籍”)足够。如果需要长文本,应该替换为TextArea

// 如果需要多行备注TextArea({placeholder:'选填,支持多行',text:this.note}).height(100)

三、搜索与筛选页面(SearchPage)

3.1 功能设计

搜索页支持两种筛选维度:

  1. 文本搜索:按快递单号、公司名、备注搜索
  2. 状态筛选:全部 / 运输中 / 已签收 / 异常

两种维度组合生效,即搜索结果同时匹配文本和状态。

3.2 数据结构

interfacePackageResult{id:number;trackingNo:string;company:string;status:string;// transit | delivered | exceptionstatusText:string;note:string;updateTime:string;}

3.3 多条件组合搜索

doSearch():void{this.hasSearched=true;letquery=this.searchQuery.toLowerCase().trim();this.searchResults=[];for(letpkgofthis.allPackages){// 条件1:文本匹配(单号/公司/备注)letmatchQuery=query.length===0||pkg.trackingNo.toLowerCase().indexOf(query)>=0||pkg.company.indexOf(query)>=0||pkg.note.indexOf(query)>=0;// 条件2:状态筛选letmatchFilter=this.selectedFilter===0||// 全部(this.selectedFilter===1&&pkg.status==='transit')||(this.selectedFilter===2&&pkg.status==='delivered')||(this.selectedFilter===3&&pkg.status==='exception');// AND 组合if(matchQuery&&matchFilter){this.searchResults.push(pkg);}}}

设计模式

  • 将"文本匹配"和"状态匹配"分开为两个布尔变量
  • &&组合,语义清晰
  • query.length === 0时不限制文本,即显示该状态筛选下的全部

3.4 标签筛选栏

privatefilterTabs:string[]=['全部','运输中','已签收','异常'];Row(){ForEach(this.filterTabs,(tab:string,index:number)=>{Text(tab).fontColor(this.selectedFilter===index?Color.White:$r('app.color.text_primary')).backgroundColor(this.selectedFilter===index?$r('app.color.primary'):$r('app.color.background')).borderRadius(16).onClick(()=>{this.onFilterClick(index);})},(tab:string)=>tab)}

选中态与未选中态的视觉区分

  • 选中:白色文字 + 主题色背景
  • 未选中:主题色文字 + 浅灰背景

3.5 搜索框与键盘交互

TextInput({placeholder:'输入单号/快递公司/备注',text:this.searchQuery}).onChange((value:string)=>{this.searchQuery=value;}).onSubmit(()=>{this.doSearch();})// 键盘回车触发搜索

onSubmit捕获键盘回车事件,提升移动端输入体验——用户输入完毕直接点回车即可搜索。

3.6 搜索状态的三种 UI

// 状态1:初始态(未搜索过)if(!this.hasSearched){// 显示引导文案}// 状态2:搜索有结果if(this.hasSearched&&this.searchResults.length>0){// 显示结果列表}// 状态3:搜索无结果if(this.hasSearched&&this.searchResults.length===0){// 显示"没有找到"空状态}

三种状态的切换必须处理好"闪烁"问题——hasSearched初始为false,用户首次点击搜索才置为true


四、快递公司管理页面(CompanyManagePage)

4.1 功能需求

  • 展示所有支持的快递公司列表
  • 可搜索过滤公司
  • 通过 Toggle 开关标记常用公司
  • 顶部显示已选数量统计

4.2 数据结构

interfaceCompanyItem{name:string;phone:string;// 客服电话website:string;// 官网isFavorite:boolean;// 是否收藏}

4.3 计算属性(getter)

// 筛选后的公司列表getfilteredCompanies():CompanyItem[]{if(!this.companies)return[];if(this.searchText.length===0)returnthis.companies;letq=this.searchText.toLowerCase();letresult:CompanyItem[]=[];for(letcofthis.companies){if(c.name.toLowerCase().indexOf(q)>=0){result.push(c);}}returnresult;}// 收藏数量getfavoriteCount():number{if(!this.companies)return0;letcount=0;for(letcofthis.companies){if(c.isFavorite)count++;}returncount;}

ArkTS 的计算属性(getter)会在每次渲染时重新求值,因此不需要额外声明@State来存储筛选结果,减少了状态同步的复杂度。

4.4 Toggle 开关组件

Toggle({type:ToggleType.Switch,isOn:company.isFavorite}).onChange(()=>{this.toggleFavorite(company.name);})

Toggle是鸿蒙原生开关组件,支持三种类型:

  • ToggleType.Switch:滑动开关(最常用)
  • ToggleType.Checkbox:复选框
  • ToggleType.Button:按钮式

⚠️ 注意:isOn是初始值,但Toggle内部会维护自己的选中状态。当用户操作时,我们需要通过toggleFavorite同步修改companies数据。

toggleFavorite(name:string):void{for(leti=0;i<this.companies.length;i++){if(this.companies[i].name===name){this.companies[i].isFavorite=!this.companies[i].isFavorite;break;}}}

由于companies是用@State装饰的数组,通过索引修改元素属性不会触发 UI 更新——但这里我们只是修改isFavorite布尔值,Toggle 组件自身维护了视觉状态,所以 UI 不会出现不同步。

如果需要确保 UI 同步,应该创建新数组:

toggleFavorite(name:string):void{this.companies=this.companies.map(c=>c.name===name?{...c,isFavorite:!c.isFavorite}:c);}

4.5 头像圆圈设计

Stack(){Circle().width(44).height(44).fill($r('app.color.primary'))Text(company.name.substring(0,1))// 取公司名的第一个字.fontSize(20).fontColor(Color.White).fontWeight(FontWeight.Bold)}

使用Stack叠放圆形背景和首字,形成类似微信头像的风格。取公司名第一个字(顺→S、圆→Y、中→Z),简单有效。


五、表单验证的最佳实践

5.1 验证时机

验证时机实现方式适用场景
实时验证onChange + 状态提示单号长度、格式
提交时验证onClick 统一校验必填项检查
失焦验证onBlur输入完成后检查

5.2 用户反馈层次

好的表单反馈应该有层次感:

🔴 单号长度不足,请检查 → 错误(阻止提交) ⚪ 请输入快递单号 → 提示(允许提交,但提交会失败) 🟢 单号格式正确 ✓ → 成功(可提交)

六、交互设计要点总结

6.1 添加包裹页

  • showPicker控制下拉展开/收起,点外侧不会自动关闭(简化实现)
  • 实时校验三个状态:未输入/错误/正确
  • 保存按钮校验后router.back()返回首页(实际项目应传递数据给首页)

6.2 搜索页

  • 文本 + 状态双维度筛选,组合使用
  • 三种 UI 状态:未搜索 / 有结果 / 无结果
  • 搜索框支持回车提交

6.3 公司管理页

  • 搜索即时过滤(onChange 触发)
  • Toggle 开关管理收藏状态
  • 顶部显示统计 “已选 N/M”
  • 公司名首字 + 圆形背景构成头像

七、小结

本篇完成了三个交互密集型页面的开发:

  1. AddPackagePage:表单输入 + 自定义选择器 + 实时验证
  2. SearchPage:多条件搜索 + 标签筛选 + 三种状态 UI
  3. CompanyManagePage:搜索过滤 + Toggle 开关 + 计算属性

核心知识点:

  • 条件渲染实现下拉选择器
  • 搜索的逻辑组合与性能
  • @State 数组修改的限制与正确方式
  • 表单验证的层次反馈设计

下一篇将进入物流时间线与历史记录,详解时间线 UI 组件的绘制、router 参数传递与接收、列表统计等高级内容。


系列索引

  • 第一篇:项目初始化与工程架构
  • 第二篇:首页与列表开发实战
  • 第三篇:表单交互与搜索筛选(本文)
  • 第四篇:物流时间线与历史记录
  • 第五篇:数据统计与个人中心
http://www.jsqmd.com/news/1006075/

相关文章:

  • BthPS3技术揭秘:Windows内核级蓝牙协议栈逆向工程实践
  • 3分钟掌握:如何将你的Scratch创意变成独立网页的终极指南
  • Kinetis SDK I2C驱动实战:从协议原理到嵌入式应用避坑指南
  • 2026厦门爱马仕包包回收横向测评|全城7家门店实测,闲置奢包安全变现攻略 - 薛定谔的梨花猫
  • Vue 2和Vue 3项目里,vue-qr的正确引入与避坑指南(附版本差异对比)
  • .NET异步编程避坑指南:Dispatcher的Invoke vs BeginInvoke,你真的用对了吗?
  • 浏览器端音乐加密格式解析技术:解锁数字音乐跨平台播放的终极方案
  • PyART:气象雷达数据分析的终极指南与完整解决方案
  • novel-downloader:一键保存全网小说,打造你的永久数字图书馆
  • NXP 56F80x DSP PWM模块核心寄存器配置与电机控制实战
  • 告别手动配IP!华为设备上DHCPv6保姆级配置教程(含OSPFv3联动)
  • 嵌入式系统稳健基石:NXP KE1xZ64看门狗与CRC模块实战配置与避坑指南
  • ARM920T架构深度解析:从哈佛架构到AMBA总线的嵌入式RISC核心设计
  • Fillinger智能填充插件:Adobe Illustrator设计师的效率革命
  • 嵌入式音频系统EMC配置实战:SDRAM、UPM与GPCM模式详解
  • 3步极速部署:i茅台自动预约系统实战指南
  • MC9328MX1 SIM模块硬件驱动解析:智能卡通信的时钟、FIFO与状态机实战
  • 打破行业信息差,包包回收真实成交价参考 - 讯息早知道
  • 别再死记硬背SPI四种模式了!用Arduino+逻辑分析仪,5分钟搞懂CPOL和CPHA
  • MC68SZ328 UART与Memory Stick协议深度解析与实战配置
  • M68HC05指令集深度解析:从寻址模式到低功耗编程实战
  • 【信息科学与工程学】【物理/化学和工程技术】第一百六十一篇 数据中心的复合材料02 GPU中的材料
  • 深入解析MMC/SD主机控制器:从硬件原理到嵌入式存储通信实战
  • 面试官最爱问的TCP灵魂五问:从三次握手到拥塞控制,一次讲清底层逻辑与避坑指南
  • 3分钟学会Blender建筑建模:Building Tools终极指南
  • 深入解析EMC外部存储器控制器:时序配置、SDRAM管理与调试实战
  • 2026安徽广告亮化工程十大品牌权威排名:新业广告99.8分领跑,全品类门头亮化首选 “安徽发光字门头制作软膜灯箱企业文化墙厂家推荐”、“安徽楼顶发光字广告位灯箱显示屏制作靠谱厂家” - 安互工业信息
  • 告别CUDA魔改!用PyTorch原生操作实现高效3D点云Transformer(DSVT实战解析)
  • 图吧工具箱下载2026最新版
  • Unity卡牌游戏UI开发终极指南:如何快速构建专业级状态机系统