查看: 165|回复: 3

鸿蒙ASCF form提交踩坑:name与checkbox数组

[复制链接]
发表于 2 小时前 | 显示全部楼层 |阅读模式
ASCF form 的使用场景很典型:设置页面上有一堆 switch,用户一次性改完点保存,开发者需要把这些值集中提交。如果不借助 form,就得逐个拿 switch 的 checked、slider 的 value、input 的内容,再拼成一个对象。form 的价值就在这一步——组件上写好 name,submit 时一次性全部收走。

ASCF form 自身只有两个事件:bindsubmit 和 bindreset。它不在页面上渲染任何可见内容,纯粹是一个数据收集容器。官方文档列出了能配合 form 使用的组件,但有一个关键前提:组件必须设置 name,没有 name 的组件在 submit 时不会出现在结果里,这是最常见的翻车原因。textarea 官方没列,但实测设置 name 后也能提交;editor 不行,它的内容只能通过 EditorContext.getContents 手动获取。

基础用法如下,注意按钮上的 form-type:submit 触发提交,reset 触发重置。form-type 忘写的话,点按钮不会发生任何事,用的时候容易误以为事件绑定错了。
  1. <form bindsubmit="formSubmit" bindreset="formReset">
  2.   <switch name="switch" checked="{{true}}" />
  3.   <radio-group name="radio">
  4.     <label><radio value="option1" />选项一</label>
  5.     <label><radio value="option2" />选项二</label>
  6.   </radio-group>
  7.   <slider name="slider" value="50" show-value />
  8.   <button form-type="submit" type="primary">提交</button>
  9.   <button form-type="reset">重置</button>
  10. </form>
复制代码
  1. Page({
  2.   formSubmit(e) {
  3.     console.info('表单数据:', e.detail.value);
  4.   },
  5.   formReset() {
  6.     console.info('表单已重置');
  7.   },
  8. });
复制代码

提交后,e.detail.value 里每个字段的类型由组件本身决定。switch 返回布尔值,radio 返回选项 value,checkbox-group 永远返回数组——哪怕只选了一个也是 ["item1"],不是 "item1"。slider 返回数字,input 返回字符串,picker 返回选中下标或日期字符串。这个数组问题在联调时特别容易踩:把单选数组直接传给后端,后端说类型不对,排查半天才发现少了一层。

实际使用中,注册和个人信息表单很适合用 form 分区域收集。基本信息里放 input、radio-group、picker,偏好设置里放 switch、checkbox-group、slider。注意 picker 与 form 配合时,提交的是选中的下标或日期字符串,不是显示文本。比如生日提交 "2000-01-01",性别提交 "male" 而不是 "男",需要显示名就自己维护映射。

电商筛选页也是典型场景:关键词、分类、价格区间、库存状态一次性组合提交。这种场景我通常不加 reset 按钮,因为用户可能已经填了很多条件,误点重置会全部清空,体验不好。注册表单加 reset,搜索筛选不加。

设置页面最常见的是一堆 switch,每个开关控制一个功能。switch 提交的是 boolean,但如果后端接口要求传 "1"/"0",就得手动转换一遍。字段多的时候这个转换很繁琐,建议抽成工具函数统一处理。

ASCF form 没有内置验证功能,必填、邮箱格式、密码长度之类都得自己写。我习惯在 submit 回调里做校验:
  1. Page({
  2.   formSubmit(e) {
  3.     const data = e.detail.value;
  4.     if (!data.nickname || !data.nickname.trim()) {
  5.       has.showToast({ title: '请输入昵称', icon: 'none' });
  6.       return;
  7.     }
  8.     if (!data.gender) {
  9.       has.showToast({ title: '请选择性别', icon: 'none' });
  10.       return;
  11.     }
  12.     if (data.hobbies && data.hobbies.length < 2) {
  13.       has.showToast({ title: '至少选择 2 个兴趣', icon: 'none' });
  14.       return;
  15.     }
  16.     // 验证通过后再提交
  17.   },
  18. });
复制代码

验证失败用 has.showToast 弹出提示,然后 return。代码多了就抽函数,别都堆在 formSubmit 里。

form 的 bindsubmit 不会像 HTML 那样刷新页面,它只是触发一个 JS 事件。数据怎么传、传到哪,完全自己控制。常见做法是在 formSubmit 里调 has.request:
  1. Page({
  2.   formSubmit(e) {
  3.     has.request({
  4.       url: 'https://api.example.com/submit',
  5.       method: 'POST',
  6.       data: e.detail.value,
  7.       success() { has.showToast({ title: '提交成功' }); },
  8.       fail() { has.showToast({ title: '提交失败', icon: 'none' }); },
  9.     });
  10.   },
  11. });
复制代码

form 只负责收集,传输交给网络层。两者不冲突。

最后总结一下踩过的坑:

第一,name 漏了就不提交。组件上没写 name,e.detail.value 里就没有这个字段,而且不报错。排查时先看每个要提交的组件有没有 name。

第二,checkbox 永远是数组。即使只选一个,拿到的也是数组,和后端对接口时确认字段类型。

第三,switch 是 boolean 不是字符串。后端要求 "1"/"0" 时自己转换。

第四,reset 后 switch 回到 checked 初始值,不是关掉。很多人以为 reset 会清空所有组件,结果 switch 还是选中状态,因为它的初始 checked 是 true。官方语义是恢复到初始状态,不是清空。

第五,picker 提交的是下标而不是文本。mode="selector" 时,拿到的是数字下标,要显示文本还得 categories[index]。

第六,form 不能嵌套。form 里再放 form,子 form 的提交行为不确定,外层 bindsubmit 也可能被干扰。不同区域要分开提交,用两个独立 form 或全手动收集。

总的来说,form 不复杂,就 bindsubmit 和 bindreset 两个事件。它的价值在于把一堆组件值一次性收齐,省去逐个 getData。但 form 不是必须的,只有一个 input 加一个按钮时,直接 bindinput 加 bindtap 手动拿值就行。字段数量超过五个再用 form,字段少了反而多此一举。
回复

使用道具 举报

发表于 2 小时前 | 显示全部楼层

Re: 鸿蒙ASCF form提交踩坑:name与checkbox数组

感谢分享,写得很详细!ASCF form 这个 name 的坑确实很常见,我一开始也漏过,后来养成习惯每个组件先写 name 再调样式。checkbox-group 返回数组那个点也深有体会,联调时后端老说类型不对,后来前端统一做了一层转换才消停。 你提到 picker 提交的是下标或日期字符串而不是显示文本,这个很关键,我一开始也以为能拿到 label,结果发现得自己维护映射关系。还有 reset 按钮在筛选页慎用这个建议很实用,之前做过一个搜索页,用户填了一堆条件不小心点到重置,气得直接反馈说体验太差。 另外关于校验,ASCF form 确实没有内置验证,我一般也是放在 submit 回调里,但字段多了会拆成单独的校验函数,比如 `validateBasic(data)`、`validatePrefs(data)`,返回错误消息或 null,这样 formSubmit 看起来干净一些。不知道你有没有在项目里抽过通用的校验工具?想听听你的实现思路。
回复 支持 反对

使用道具 举报

发表于 2 小时前 | 显示全部楼层

Re: 鸿蒙ASCF form提交踩坑:name与checkbox数组

楼主总结得很到位,尤其是 checkbox-group 返回数组这个坑,联调时确实容易忽略,明明只选一项,后端却收到数组。name 漏了不提交这个也是新手最容易犯的,我一开始也栽在这上面。 另外验证部分自己写确实麻烦,但 form 本身不做校验也合理,毕竟场景太多。抽工具函数那个思路挺实用的,我后面也打算这么干。
回复 支持 反对

使用道具 举报

发表于 2 小时前 | 显示全部楼层

Re: 鸿蒙ASCF form提交踩坑:name与checkbox数组

感谢分享,写得很实在。ASCF form 这个 name 的坑我当初也踩过,组件没设置 name 直接不出现,排查半天还以为是事件没绑上。checkbox-group 永远返回数组这个确实容易在和后端联调时被问“怎么传了个数组过来”,后来我干脆前端先转换好再提交。 还有 switch 的布尔值转 0/1 那个,字段一多真的烦,抽工具函数是正解。picker 提交的是下标或日期字符串而不是显示文本,这个我也遇到过,尤其是自定义 range 的时候,拿到的 index 还得自己对应回数组。 另外想补充一点:reset 事件触发后,switch 和 input 这些会不会自动恢复成初始状态?我实测好像不是所有组件都能重置干净,有时还得手动处理。不知道你有没有遇到类似情况?
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

指导单位

江苏省公安厅

江苏省通信管理局

浙江省台州刑侦支队

DEFCON GROUP 86025

Hacking Group 021A

旗下站点

态势感知中心

应急响应中心

红盟安全

联系我们

官方QQ群:112851260

官方邮箱:security#ihonker.org(#改成@)

官方核心成员

关注微信公众号

Archiver|手机版|小黑屋| ( 沪ICP备2021026908号 )

GMT+8, 2026-8-12 16:27 , Processed in 0.025111 second(s), 18 queries , Gzip On, Redis On.

Powered by ihonker.com

Copyright © 2015-现在.

  • 返回顶部