作者:easonruan
笔者目前正在开发一个涉及较多表单的场景的新项目。但由于是新项目进度赶,产品人员紧缺,表单需求往往没有考虑得很周全。
那作为一名前端开发,如何辅助产品尽可能让表单需求一次即通关,减少反复沟通以及提缺陷修缺陷的时间,从而加快项目进度?
以下是笔者在项目中在表单开发方面的一些总结:
以下演示案例为vue项目,组件库为element-ui
1. 重视通用型表单验证
业务场景:
表单中如果涉及手机号码,因为手机号码是特殊场景,我们很容易想到特殊的校验规则——手机号的正则校验。
然而对于一个通用型字段,如标题 title 、描述 desc 等基本的字段,它们实在太普通太一般,导致我们放松了警惕。
导致问题:开发与测试反复在 tapd
提缺陷修缺陷,在一堆小问题上浪费了大量时间,工作效率低。
解决方法:
- 避免用户的输入前后有空格,即trim
- 限制最大输入长度,即max-length
- 不能包含特殊字符,即emoji表情是否能输入等
-
// form rules
-
export default {
-
title: [
-
/**
-
* Tips 避免用户的输入前后有空格
-
* 可以使用 v-model.trim 指令自动清除用户前后空格,
-
* 技术手段能解决的,我们避免提示用户
-
**/
-
{ max: 50, message: '不能超过50个字', trigger: 'blur' },
-
{
-
pattern: /^[ -~ 一-龥 -。 - -〗]+$/,
-
// - 基本拉丁字母 https://unicode-table.com/cn/blocks/basic-latin/
-
// 一-龥 中文 https://unicode-table.com/cn/blocks/cjk-unified-ideographs/
-
// -。 半角及全角形式字符 https://unicode-table.com/cn/blocks/halfwidth-and-fullwidth-forms/
-
// - 英文标点 https://unicode-table.com/cn/blocks/general-punctuation/
-
// -〗 中文标点 https://unicode-table.com/cn/blocks/cjk-symbols-and-punctuation/
-
message: "不能包含特殊字符",
-
trigger: "blur"
-
}
-
]
-
}
2. 避免重复提交
业务场景:当用户快速点击提交按钮,导致问题:页面会重复发请求给后端。
解决方法虽然很简单,但这却是开发最容易忽略的,也是tapd上最经常见的缺陷问题。
解决方法一:在业务代码执行完之前不能再次触发
-
export default {
-
methods: {
-
onSubmit () {
-
// 可以与Loading搭配使用
-
if (this.isCommitting) return;
-
this.isCommitting = true;
-
// 表单验证以及业务请求代码
-
this.isCommitting = false;
-
},
-
}
-
}
解决方法二:经过评论的提醒,遗漏了利用 debounce
防抖实现防二次点击操作。
-
export default {
-
mounted() {
-
// `_.debounce` 是一个通过 Lodash 限制操作频率的函数。
-
this.debouncedSaveForm = _.debounce(
-
this.onSubmit, // 回调函数
-
500, // 时间窗口的间隔
-
{
-
leading: true, // 点击立即执行
-
trailing: false // 延迟时间过后不执行
-
}
-
);
-
},
-
methods: {
-
onSubmit () {
-
if (this.isCommitting) return;
-
this.isCommitting = true;
-
// 表单验证以及业务请求代码
-
this.isCommitting = false;
-
},
-
}
-
}
3. 表单提交或出错时的Loading提示
业务场景:表单提交后没展示Loading导致问题:当请求request较久时,页面像是卡死了,没任何响应,用户体验很差。
业务场景:遇到错误时没隐藏Loading导致问题:当请求request出错时,Loading没关闭,页面流程进行不下去。
解决方案:
-
export default {
-
methods: {
-
onSubmit () {
-
// 容易忽略一:发送请求前,没展示Loading
-
this.$loading.show('努力加载中...');
-
request('apiUrl', data)
-
.then(() => {})
-
.catch(err => {
-
// 容易忽略二:请求出错时,没隐藏Loading
-
this.$loading.hide();
-
})
-
},
-
}
-
}
4. 表单重新打开时,要重置表单数据
业务场景:如果表单是属于弹窗 Dialog 内,部分开发为了代码可复用性,新增和编辑是共用同一个表单代码。
导致问题:用户在编辑某一条数据后,再点击新增,会发现新增表单里面的内容是上一条编辑内容的数据。
解决方案:
-
export default {
-
mounted() {
-
// 页面初始化时,先备份表单数据
-
this._bak_form = _.cloneDeep(this.form);
-
},
-
methods: {
-
onOpenDialog(actionType, tableRowIndex, data) {
-
if (actionType === "add") {
-
// 新增时,需要恢复为默认数据
-
this.form = _.cloneDeep(this._bak_form);
-
/**
-
* Tips
-
* 这里不能用解构 this.form = {...this._bak_form},
-
* 不然会导致,改了form里面的(object或array类型)数据,同时会影响到_bak_form的数据
-
* 这是因为引用数据类型的指针还是指向同一个地址。
-
**/
-
} else if (actionType === "edit") {
-
// 编辑
-
this.tableRowIndex = tableRowIndex;
-
this.form = _.cloneDeep(data);
-
}
-
this.actionType = actionType;
-
this.visible = true;
-
},
-
}
-
}
Tips 避免在关闭窗口时恢复为默认数据
- 造成问题:恢复为默认数据会触发表单校验规则,因此会有显眼的警告“XX不能为空”。
- 触发原因:与此同时,窗口的visible变为false,假若窗口的隐藏式有过渡效果的话,窗口隐藏需要500ms,而重置表单是立即生效的,用户是会看到一闪而过的红色警告。
- 解决方法: 一是避免在关闭窗口时恢复为默认数据 二是使用
resetFields
将所有字段值重置为初始值并移除校验结果(但不能解决点编辑后再点新增时,恢复为默认数据)
5. 不小心点击关闭页面时,要提示让用户确认
业务场景:当用户在填写一个长表单时,手误点了关闭页面或者点击去到其他页面。
导致问题:用户花时间填写的表单数据会丢失,用户又要重新填一遍。用户体验大大降低。
解决方法:
-
export default {
-
watch: {
-
"visible": value => {
-
if (!value) {
-
// 当弹窗关闭不涉及表单时,清除事件
-
window.onbeforeunload = null;
-
return;
-
}
-
// 当弹窗显示有表单数据时,网页跳转或者关闭时提醒用户
-
window.onbeforeunload = e => (e.returnValue = "确定离开当前页面?");
-
}
-
},
-
}
总结
最后,我汇总一下上面5个技巧点的真实场景Demo:
以上都不是什么新内容,但如果工作中能重视并注意到这些细节问题,就能一次即通关表单开发需求,减少与产品测试反复沟通的时间,加快项目的进度。
不然等到产品或测试临下班前发现这些问题时,会出现这样的场景:开发被拖着对着屏幕敲代码修缺陷,测试重新打开缺陷,反复循环N次。
N=上面提到的5个技巧点
中华人民共和国消防法第二条是 “消防工作贯彻预防为主,防消结合的方针”
,放在需求开发上也是一样道理:**提前发现提前修复才能避免当代码发生“火灾”时的一团乱。
关注我们
IMWeb 团队隶属腾讯公司,是国内最专业的前端团队之一。
我们专注前端领域多年,负责过 QQ 资料、QQ 注册、QQ 群等亿级业务。目前聚焦于在线教育领域,精心打磨 腾讯课堂 及 企鹅辅导 两大产品。