HarmonyOS实现表单页面的输入,必填校验和提交

一. 样例介绍

本篇Codelab基于input组件、label组件和dialog组件,实现表单页面的输入、必填校验和提交:

  1. 为input组件设置不同类型(如:text,email,date等),完成表单页面。

  2. 对表单页面中的用户名、电子邮件、爱好输入框进行必填校验。

  3. 使用弹框选择性别、爱好。

相关概念

input组件:交互式组件,包括单选框,多选框,按钮和单行文本输入框。

label组件:为input、button、textarea组件定义相应的标注,点击该标注时会触发绑定组件的点击效果。

dialog组件:自定义弹窗容器。

完整示例

gitee源码地址

二. 环境搭建

我们首先需要完成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中提供。

less 复制代码
├──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                    // 应用静态资源目录

四. 页面设计

页面包括用户名、电子邮箱、出生日期、身高、性别、爱好输入框和提交按钮,点击提交按钮进行必填校验。

ini 复制代码
<!-- 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>
    <div class="input-area">
        <image src="{{ urls.hobby }}"></image>
        <div class="input-label">
            <image src="{{ urls.required }}"></image>
            <label class="label" target="hobbies">{{ $t('strings.hobbies') }}</label>
        </div>
        <div class="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>

效果如图所示:

点击性别输入框弹出性别单选框,点击爱好输入框弹出爱好多选框。

xml 复制代码
<!-- 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>
            <div class="button">
                <text onclick="closeHobby">{{ $t('strings.cancel') }}</text>
                <divider vertical="true"></divider>
                <text onclick="confirmHobby">{{ $t('strings.determined') }}</text>
            </div>
        </div>
    </dialog>
</div>

效果如图所示:

五. 后台逻辑处理

用户名、电子邮箱、出生日期、身高输入框中值发生变化时,会在data对象中实时更新。

ini 复制代码
// 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;
    }
  },
  ...
}

通过自定义弹框选择性别、爱好。在弹框中点击取消按钮关闭当前弹框,点击确定按钮先设置所选值再关闭弹框。

javascript 复制代码
// 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"格式校验、对身高进行整数或浮点数校验。

kotlin 复制代码
// 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组件的使用。

相关推荐
JasonYin~2 小时前
HarmonyOS NEXT 实战之元服务:静态案例效果--- 手机一键加速、手机垃圾清理
华为·harmonyos
Freerain999 小时前
鸿蒙Next类属性观测器V2
华为·harmonyos
yg_小小程序员10 小时前
鸿蒙开发(16)使用DevEco Studio上的Git工具进行多远程仓管理
git·华为·harmonyos
JasonYin~11 小时前
HarmonyOS NEXT 实战之元服务:静态案例效果---每日玩机技巧
harmonyos
轻口味11 小时前
【每日学点鸿蒙知识】多线程限制、axios组件下载进度问题、lpx问题、Web组件全局代理、ArrayList问题
华为·harmonyos
yuanlaile11 小时前
纯Dart Flutter库适配HarmonyOS
flutter·华为·harmonyos·flutter开发鸿蒙·harmonyos教程
yuanlaile11 小时前
Flutter开发HarmonyOS 鸿蒙App的好处、能力以及把Flutter项目打包成鸿蒙应用
flutter·华为·harmonyos·flutter开发鸿蒙
JasonYin~11 小时前
HarmonyOS NEXT 实战之元服务:静态案例效果---手机查看电量
android·华为·harmonyos
李游Leo12 小时前
探索HarmonyOS Next API 13 :Camera API 照相机功能实战
harmonyos
编程百晓君19 小时前
一文彻底拿捏DevEco Studio的使用小技巧
华为·harmonyos