HarmonyOS实现表单页面的输入,必填校验和提交
一. 样例介绍
本篇Codelab基于input组件、label组件和dialog组件,实现表单页面的输入、必填校验和提交:
1. 为input组件设置不同类型(如:text,email,date等),完成表单页面。
2. 对表单页面中的用户名、电子邮件、爱好输入框进行必填校验。
3. 使用弹框选择性别、爱好。
相关概念
● input组件:交互式组件,包括单选框,多选框,按钮和单行文本输入框。
● label组件:为input、button、textarea组件定义相应的标注,点击该标注时会触发绑定组件的点击效果。
● dialog组件:自定义弹窗容器。
完整示例
二. 环境搭建
我们首先需要完成HarmonyOS开发环境搭建,可参照如下步骤进行。
软件要求
● DevEco Studio版本:DevEco Studio 3.1 Release及以上版本。
● HarmonyOS SDK版本:API version 9及以上版本。
硬件要求
● 设备类型:华为手机或运行在DevEco Studio上的华为手机设备模拟器。
● HarmonyOS系统:3.1.0 Developer Release及以上版本。
环境搭建
1. 安装DevEco Studio,详情请参考下载和安装软件。
2. 设置DevEco Studio开发环境,DevEco Studio开发环境需要依赖于网络环境,需要连接上网络才能确保工具的正常使用,可以根据如下两种情况来配置开发环境:
● 如果可以直接访问Internet,只需进行下载HarmonyOS SDK操作。
● 如果网络不能直接访问Internet,需要通过代理服务器才可以访问,请参考配置开发环境。
1. 开发者可以参考以下链接,完成设备调试的相关配置:
● 使用真机进行调试
三.代码结构解读
本篇Codelab只对核心代码进行讲解,对于完整代码,我们会在源码下载或gitee中提供。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | ├──entry/src/main/js // 代码区 │ └──MainAbility │ ├──common │ │ ├──constant │ │ │ └──commonConstants.js // 公共常量 │ │ └──images // 图片资源目录 │ ├──i18n │ │ ├──en-US.json // 英文国际化 │ │ └──zh-CN.json // 中文国际化 │ ├──pages │ │ └──index │ │ ├──index.css // 表单页面样式 │ │ ├──index.hml // 表单页面 │ │ └──index.js // 表单页面逻辑 │ └──app.js // 程序入口 └──entry/src/main/resource // 应用静态资源目录 |
四. 页面设计
页面包括用户名、电子邮箱、出生日期、身高、性别、爱好输入框和提交按钮,点击提交按钮进行必填校验。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 | <!-- index.hml --> <div class = "container" > ... <div class = "user-area" > <image class = "image" src= "{{ urls.user }}" ></image> <div class = "input-label" > <image src= "{{ urls.required }}" ></image> <label class = "label" target= "user" >{{ $t( 'strings.user' ) }}</label> </div> <div class = "input-div" > <input class = "input" id= "user" type= "text" placeholder= "{{ $t('strings.user') }}" onchange= "inputChange" ontranslate= "translate" ></input> </div> </div> <div class = "input-area" > <image src= "{{ urls.email }}" ></image> <div class = "input-label" > <image src= "{{ urls.required }}" ></image> <label class = "label" target= "email" >{{ $t( 'strings.email' ) }}</label> </div> <div class = "input-div" > <input class = "input" id= "email" type= "email" placeholder= "{{ $t('strings.email') }}" onchange= "inputChange" > </input> </div> </div> <div class = "input-area" > <image src= "{{ urls.date }}" ></image> <div class = "input-label" > <label class = "label" target= "date" >{{ $t( 'strings.birthday' ) }}</label> </div> <div class = "input-div" > <input class = "input" id= "date" type= "date" placeholder= "{{ $t('strings.date') }}" onchange= "inputChange" > </input> </div> </div> <div class = "input-area" > <image src= "{{ urls.height }}" ></image> <div class = "input-label" > <label class = "label" target= "height" >{{ $t( 'strings.height_holder' ) }}</label> </div> <div class = "input-div" > <input class = "input" id= "height" type= "number" placeholder= "{{ $t('strings.height') }}" onchange= "inputChange" ></input> </div> </div> <div class = "input-area" > <image src= "{{ urls.gender }}" ></image> <div class = "input-label" > <label class = "label" target= "gender" >{{ $t( 'strings.gender' ) }}</label> </div> <div class = "input-div" onclick= "openGender" > <input class = "input select" id= "gender" type= "text" placeholder= "{{ $t('strings.gender') }}" softkeyboardenabled= "false" value= "{{ genderObj[gender] }}" ></input> <image src= "{{ urls.spinner }}" ></image> </div> </div> <divclass= "input-area" > <image src= "{{ urls.hobby }}" ></image> <divclass= "input-label" > <image src= "{{ urls.required }}" ></image> <labelclass= "label" target= "hobbies" >{{ $t( 'strings.hobbies' ) }}</label> </div> <divclass= "input-div" onclick= "openHobby" > <input class = "input select" id= "hobbies" type= "text" placeholder= "{{ $t('strings.hobby') }}" softkeyboardenabled= "false" value= "{{ hobbies.join(',') }}" ></input> <image src= "{{ urls.spinner }}" ></image> </div> </div> <button type= "capsule" onclick= "buttonClick" >{{ $t( 'strings.submit' ) }}</button> ... </div> |
效果如图所示:
点击性别输入框弹出性别单选框,点击爱好输入框弹出爱好多选框。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 | <!-- index.hml --> <div class = "container" > ... <dialog id= "genderDialog" > <div class = "gender-dialog" > <text>{{ $t( 'strings.gender_select' ) }}</text> <div> <text>{{ $t( 'strings.gender_male' ) }}</text> <input if = "{{ gender === 0 }}" class = "radio" type= "radio" checked = "true" name= "radio" value= "{{ $t('strings.gender_male') }}" onchange= "onRadioChange" ></input> <input if = "{{ gender === 1 }}" class = "radio" type= "radio" checked = "false" name= "radio" value= "{{ $t('strings.gender_male') }}" onchange= "onRadioChange" ></input> </div> <divider vertical= "false" ></divider> <div> <text>{{ $t( 'strings.gender_female' ) }}</text> <input if = "{{ gender === 0 }}" class = "radio" type= "radio" checked = "false" name= "radio" value= "{{ $t('strings.gender_female') }}" ></input> <input if = "{{ gender === 1 }}" class = "radio" type= "radio" checked = "true" name= "radio" value= "{{ $t('strings.gender_female') }}" ></input> </div> <div class = "button" > <text onclick= "closeGender" >{{ $t( 'strings.cancel' ) }}</text> <divider vertical= "true" ></divider> <text onclick= "confirmGender" >{{ $t( 'strings.determined' ) }}</text> </div> </div> </dialog> <dialog id= "hobbyDialog" > <div class = "hobby-dialog" > <text>{{ $t( 'strings.hobby' ) }}</text> <div> <text>{{ $t( 'strings.hobby_swim' ) }}</text> <input class = "checkbox" type= "checkbox" checked = "{{ hobbies.indexOf(hobbiesOjb[0]) !== -1 }}" value= "{{ hobbiesOjb[0] }}" onchange= "checkboxOnChange" ></input> </div> <div> <text>{{ $t( 'strings.hobby_fitness' ) }}</text> <input class = "checkbox" type= "checkbox" checked = "{{ hobbies.indexOf(hobbiesOjb[1]) !== -1 }}" value= "{{ hobbiesOjb[1] }}" onchange= "checkboxOnChange" ></input> </div> <div> <text>{{ $t( 'strings.hobby_soccer' ) }}</text> <input class = "checkbox" type= "checkbox" checked = "{{ hobbies.indexOf(hobbiesOjb[2]) !== -1 }}" value= "{{ hobbiesOjb[2] }}" onchange= "checkboxOnChange" ></input> </div> <div> <text>{{ $t( 'strings.hobby_basketball' ) }}</text> <input class = "checkbox" type= "checkbox" checked = "{{ hobbies.indexOf(hobbiesOjb[3]) !== -1 }}" value= "{{ hobbiesOjb[3] }}" onchange= "checkboxOnChange" ></input> </div> <div> <text>{{ $t( 'strings.hobby_reading_book' ) }}</text> <input class = "checkbox" type= "checkbox" checked = "{{ hobbies.indexOf(hobbiesOjb[4]) !== -1 }}" value= "{{ hobbiesOjb[4] }}" onchange= "checkboxOnChange" ></input> </div> <divclass= "button" > <text onclick= "closeHobby" >{{ $t( 'strings.cancel' ) }}</text> <divider vertical= "true" ></divider> <text onclick= "confirmHobby" >{{ $t( 'strings.determined' ) }}</text> </div> </div> </dialog> </div> |
效果如图所示:
五. 后台逻辑处理
用户名、电子邮箱、出生日期、身高输入框中值发生变化时,会在data对象中实时更新。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | // index.js export default { data: { ... user: '' , email: '' , date: '' , height: '' , ... }, ... // 实时保存输入框内容 inputChange( event ) { let idName = event .target.id; if (idName === CommonConstants.USER) { this .user = event .value; } else if (idName === CommonConstants.EMAIL) { this .email = event .value; } else if (idName === CommonConstants.DATE) { this .date = event .value; } else if (idName === CommonConstants.HEIGHT) { this .height = event .value; } }, ... } |
通过自定义弹框选择性别、爱好。在弹框中点击取消按钮关闭当前弹框,点击确定按钮先设置所选值再关闭弹框。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 | // index.js export default { data: { ... genderObj: [], genderTemp: 0, gender: 0, hobbiesOjb: [], hobbiesTemp: [], hobbies: [] }, ... // 打开性别弹框 openGender() { this .$element( 'genderDialog' ).show(); }, // 重新选择性别 onRadioChange( event ) { if ( event . checked ) { this .genderTemp = 0; } else { this .genderTemp = 1; } }, // 关闭性别弹框 closeGender() { this .$element( 'genderDialog' ).close(); }, // 性别弹框中点击“确定” confirmGender() { this .gender = this .genderTemp; this .closeGender(); }, // 打开爱好弹框 openHobby() { this .$element( 'hobbyDialog' ).show(); }, // 关闭爱好弹框 closeHobby() { this .$element( 'hobbyDialog' ).close(); }, // 在爱好弹开中点击“确定” confirmHobby() { let that = this ; let copyHobbies = Object.create(Object.getPrototypeOf( this .hobbiesTemp)); Object.getOwnPropertyNames( this .hobbiesTemp).forEach((items) => { let item = Object.getOwnPropertyDescriptor(that.hobbiesTemp, items); Object.defineProperty(copyHobbies, items, item); }) this .hobbies = copyHobbies; this .closeHobby(); }, ... // 选择爱好 checkboxOnChange( event ) { let currentVal = event .currentTarget.attr.value; if ( event . checked ) { this .hobbiesTemp.push(currentVal); } else { this .hobbiesTemp = this .hobbiesTemp.filter(item => { return item !== currentVal; }); } }, ... } |
点击提交按钮对表单进行提交前,先对用户名、密码、电子邮件、爱好进行必填校验,再通过正则表达式对出生日期进行“yyyy-mm-dd”格式校验、对身高进行整数或浮点数校验。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | // index.js export default { ... // 表单提交验证 buttonClick() { if ( this .user === '' ) { this .showPrompt( this .$t( 'strings.user_check_null' )); return ; } if ( this .email === '' ) { this .showPrompt( this .$t( 'strings.email_check_null' )); return ; } if ( this .hobbies.length === 0) { this .showPrompt( this .$t( 'strings.hobby_check_null' )); return ; } if (( this .date !== '' ) && (! this .checkDateInput( this .date))) { this .showPrompt( this .$t( 'strings.date_not_format' )); return ; } if (( this .height !== '' ) && (! this .checkHeight( this .height))) { this .showPrompt( this .$t( 'strings.height_not_format' )); return ; } this .showPrompt( this .$t( 'strings.success' )); }, ... // 表单验证结果 showPrompt(msg) { prompt.showToast({ message: msg, duration: CommonConstants.DURATION }); }, ... } |
总结
您已经完成了本次Codelab的学习,并了解到以下知识点:
1. input组件的使用。
2. label组件的使用。
3. dialog组件的使用。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了