鸿蒙掌上驾考宝典应用开发38:用个人信息组件——collect_personal_info

发布时间:2026/8/18 2:19:31
鸿蒙掌上驾考宝典应用开发38:用个人信息组件——collect_personal_info 第38篇通用个人信息组件——collect_personal_info一、引言个人信息编辑是几乎每个应用都需要的功能包括头像、昵称、手机号、出生日期等信息的编辑和展示。DriverLicenseExam 项目的collect_personal_info组件将这些功能封装为可复用的组件集合支持多种输入类型和表单校验。本文将深入解析其实现。二、组件架构2.1 目录结构collect_personal_info/ ├──src/main/ets/ │ ├── common/ │ │ ├── ConfigModel.ets← 配置模型 │ │ ├── Constant.ets← 常量 │ │ ├── CustomModifier.ets← 自定义修饰器 │ │ ├── DataModel.ets← 数据模型 │ │ ├── ErrorMsgMap.ets← 错误信息映射 │ │ ├── FormModel.ets← 表单模型 │ │ ├── GridRowColSetting.ets← 网格布局设置 │ │ ├── Util.ets← 工具类 │ │ └── WindowModel.ets← 窗口模型 │ ├── components/ │ │ ├── ChooseAvatar.ets← 头像选择 │ │ ├── ChooseDate.ets← 日期选择 │ │ ├── EnterPhoneNumber.ets← 手机号输入 │ │ ├── EnterTextArea.ets← 多行文本输入 │ │ ├── EnterTextInput.ets← 单行文本输入 │ │ └── SelectDialog.ets← 选择弹窗 │ ├── viewmodels/ │ │ └── PersonalInfoViewVM.ets← 个人信息 ViewModel │ └── views/ │ ├── PersonalInfoView.ets← 个人信息视图 │ └── ListCard.ets← 列表卡片 ├── Index.ets← 模块导出 └── oh-package.json5← 模块配置2.2 组件关系PersonalInfoView主视图 ├── ListCard列表卡片容器 │ ├── ChooseAvatar头像编辑 │ ├── EnterTextInput昵称编辑 │ ├── ChooseDate出生日期 │ ├── EnterPhoneNumber手机号 │ └── EnterTextArea个人简介 └── SelectDialog选择弹窗三、头像编辑3.1 ChooseAvatar 组件// ChooseAvatar.etsComponentV2exportstructChooseAvatar{Localavatar:Resource $r(app.media.user_avatar);LocalshowActionSheet:booleanfalse;build() {Column() {Stack() {// 头像图片Image(this.avatar) .width(80).height(80) .borderRadius(40) .objectFit(ImageFit.Cover);// 编辑图标Image($r(app.media.ic_edit_avatar)) .width(24).height(24) .position({right:0,bottom:0}); } .onClick(() {this.showActionSheettrue; }) .bindActionSheet(this.showActionSheet, {sheets: [ {title:拍照,action:() {PickerUtil.takePhoto().then((uri:string) {this.avatar uri; }); }, }, {title:从相册选择,action:() {PickerUtil.pickImage().then((uri:string) {this.avatar uri; }); }, }, {title:取消,action:() {}, }, ], });Text(点击更换头像) .fontSize(12) .fontColor(#999) .margin({top:8}); } .width(100%) .alignItems(HorizontalAlign.Center); } }3.2 PickerUtil 工具// PickerUtil.etsexportclassPickerUtil{// 从相册选择图片staticasyncpickImage(): Promisestring{try{constphotoPicker newphotoAccessHelper.PhotoViewPicker();constresult awaitphotoPicker.select({ MIME_TYPE: [image/jpeg,image/png], maxSelectNumber:1, });returnresult.photoUris[0]; }catch(error) { Logger.error(PickerUtil,pickImage failed: error.message);return; } }// 拍照staticasynctakePhoto(): Promisestring{try{// 调用相机拍照// 返回图片 URIreturn; }catch(error) { Logger.error(PickerUtil,takePhoto failed: error.message);return; } } }四、表单编辑组件4.1 单行文本输入// EnterTextInput.etsComponentV2export struct EnterTextInput {Paramlabel: string ;// 标签名Paramplaceholder: string ;// 占位符ParammaxLength: number 20;// 最大长度Paramvalidator?: (value: string) string;// 校验函数Localvalue: string ;// 输入值LocalerrorMsg: string ;// 错误信息build() { Column() { Row() {// 标签Text(this.label) .fontSize(14) .width(80) .fontColor($r(sys.color.font_primary));// 输入框TextInput({ placeholder:this.placeholder, text:this.value, }) .layoutWeight(1) .maxLength(this.maxLength) .onChange((value: string) {this.value value;this.validate(); }); } .padding(12) .height(46);// 错误提示if(this.errorMsg) { Text(this.errorMsg) .fontSize(12) .fontColor(#FF6B6B) .margin({ left:92, bottom:4}); } } } validate() {if(this.value.length 0) {this.errorMsg 请输入this.label; }elseif(this.validator) {this.errorMsg this.validator(this.value); }else{this.errorMsg ; } } }4.2 手机号输入// EnterPhoneNumber.etsComponentV2export struct EnterPhoneNumber {LocalphoneNumber: string ;LocalerrorMsg: string ; build() { Column() { Row() { Text(手机号).fontSize(14).width(80); TextInput({ placeholder:请输入手机号, text:this.phoneNumber, }) .layoutWeight(1) .type(InputType.PhoneNumber)// 手机号输入类型.maxLength(11) .onChange((value: string) {this.phoneNumber value;this.validatePhone(); }); } .padding(12) .height(46);if(this.errorMsg) { Text(this.errorMsg).fontSize(12).fontColor(#FF6B6B); } } } validatePhone() {constphoneRegex /^1[3-9]\d{9}$/;if(this.phoneNumber.length 0) {this.errorMsg 请输入手机号; }elseif(!phoneRegex.test(this.phoneNumber)) {this.errorMsg 请输入正确的手机号格式; }else{this.errorMsg ; } } }4.3 日期选择// ChooseDate.etsComponentV2exportstructChooseDate{Paramlabel:string出生日期;LocalselectedDate:DatenewDate();LocalshowDatePicker:booleanfalse;build() {Row() {Text(this.label).fontSize(14).width(80);Text(this.formatDate(this.selectedDate)) .fontSize(14) .fontColor($r(sys.color.font_primary)) .layoutWeight(1); } .padding(12) .height(46) .onClick(() {this.showDatePickertrue; }) .bindDatePicker($$this.showDatePicker, {start:newDate(1900-01-01),end:newDate(),selected:this.selectedDate, }); }formatDate(date:Date):string{constyear date.getFullYear();constmonth String(date.getMonth() 1).padStart(2,0);constday String(date.getDate()).padStart(2,0);returnyear - month - day; } }五、个人信息主视图5.1 PersonalInfoView 组件// PersonalInfoView.etsComponentV2export struct PersonalInfoView {LocaluserInfo: UserInfoModel AccountUtil.getUserInfo(); build() { NavDestination() { Scroll() { Column({ space:12}) {// 头像模块ListCard({ content: ChooseAvatar({ avatar:this.userInfo.avatar }), });// 信息编辑模块ListCard({ content: Column({ space:0}) { EnterTextInput({ label:昵称, placeholder:请输入昵称, value:this.userInfo.nicknameasstring, maxLength:12, }); Divider().height(0.5).width(100%); ChooseDate({ label:出生日期}); Divider().height(0.5).width(100%); EnterPhoneNumber({ phoneNumber:this.userInfo.phone }); }, });// 保存按钮Button(保存) .width(90%) .height(44) .backgroundColor(#64BB5C) .borderRadius(22) .fontColor(#fff) .fontSize(16) .margin({ top:24}) .onClick(() {this.saveUserInfo(); }); } .padding(16); } } .title(个人信息); } saveUserInfo() {// 保存用户信息AccountUtil.setUserInfo(this.userInfo); showToast(保存成功,this.getUIContext());this.vm.navStack.pop(); } }六、表单校验与错误处理6.1 错误信息映射// ErrorMsgMap.etsexportconstErrorMsgMap: Recordstring,string {empty_nickname:昵称不能为空,invalid_phone:手机号格式不正确,invalid_date:请选择有效的日期,nickname_too_long:昵称长度不能超过12个字符,phone_exists:该手机号已被绑定, };6.2 表单提校验// 表单提交前校验validateForm(): boolean { let isValid true;// 校验所有字段if(!this.userInfo.nickname) { showToast(请输入昵称,this.getUIContext()); isValid false; }if(!this.isValidPhone(this.userInfo.phone)) { showToast(请输入正确的手机号,this.getUIContext()); isValid false; }returnisValid; }七、总结个人信息组件通过多个子组件的组合实现了完整的个人信息编辑功能头像编辑支持拍照和相册选择文本输入支持单行和多行文本手机号输入专门的手机号格式校验日期选择使用 DatePicker 组件表单校验实时的输入校验和错误提示保存交互保存成功后的 Toast 提示关键源码文件components/collect_personal_info/src/main/ets/views/PersonalInfoView.ets— 主视图components/collect_personal_info/src/main/ets/components/ChooseAvatar.ets— 头像选择components/collect_personal_info/src/main/ets/components/EnterTextInput.ets— 文本输入components/collect_personal_info/src/main/ets/components/ChooseDate.ets— 日期选择components/collect_personal_info/src/main/ets/components/EnterPhoneNumber.ets— 手机号输入commons/commonLib/src/main/ets/utils/PickerUtil.ets— 图片选择工具