前端各框架表单最佳实践

表单提交规范

表单提交是用户主动触发的一种操作,用于搜集不同类型的用户输入。

在开发早期没有 ajax,主要依靠 form 表单通过编辑 action, method 属性通过页面跳转完成数据的收集

现代 form 表单更多的是指 JS 对象中的 form 对象,通过劫持其 onSubmit 事件进行数据校验和提交

注意事项

表单提交应是多方位触发的

表单提交都应由表单的 submit 事件触发,它可能是由 Button(type:submit)| input(type:submit)按钮,在表单直接按下回车键或是在移动端用软键盘按下提交键

因为提交维度众多所以我们应该将处理方法集中到 onSubmit 方法中,又因为表单设计之初是要页面跳转的所以我们要 preventDefault 阻止默认行为

Vue 中通过.prevent 修饰符可以直接阻止表单默认行为

<template>
  <div>
    <form @submit.prevent="handleSubmit">
      <!-- 表单域 -->
    </form>
  </div>
</template>

表单可输入域的值应做 trim 操作

表单内用户可随意输入的表单域应在提交时做 空格 trim 处理

Vue 中通过 trim 修饰符可以很轻松的处理空格

<template>
  <div>
    <input v-model.trim="form.name" />
  </div>
</template>

中间状态

表单内可以显示触发提交的按钮应加入中间状态控制重复提交

Vue

<template>
  <button :disabled="submitting"></button>
</template>

防抖 Debounce

防抖的原理:你尽管触发事件,但是我一定在事件触发的 n 秒之后才执行,如果你在触发事件 n 秒内又触发了这个事件,那我就以新的事件的时间为准,n 秒之后在执行。

form表单提交加入防抖
Vue

//一种方法 在api层加防抖: 
import { debounce } from 'lodash'
export const pressDebounce = debounce(function deleteReturnData(data) {
  return request.post('/return/deleteCsReturnData/', {
    data
  })
}, 2000)

export default {
  methods: {
    async handleSubmit() {
      if (!this.submitting) {
        try {
          await this.$refs.ruleForm.validate()
          this.submitBtn()
        } catch (e) {
          console.error(e)
        }
      }
    },
    async submitBtn() {
      try {
        this.submitting = true
        const res = await pressDebounce({ returnBatchId: 1 })
      } catch (e) {
        console.error(e)
      } finally {
        this.submitting = false
      }
    },
  },
}

// 第二种在事件上加防抖
// 必须是事件名:  的写法  例如: handleSubmit: debounce
// 不能采用箭头函数形式()=>{},这样 this.$refs和this.form报错
// 原因是箭头函数绑定了父级作用域的上下文,所以 this 将不会按照期望指向 Vue 实例,this.searchContractSuppList 将是 undefined 可参考https://cn.vuejs.org/v2/api#methods。
import { debounce } from 'lodash'
export default {
  methods: {
      handleSubmit: debounce(async function () {
      if (!this.submitting) {
        try {
          await this.$refs.ruleForm.validate()
          this.submitBtn()
        } catch (e) {
          console.error(e)
        }
      }
    }, 1000),
    async submitBtn() {
      try {
        this.submitting = true
        const res = await pressDebounce({ returnBatchId: 1 })
      } catch (e) {
        console.error(e)
      } finally {
        this.submitting = false
      }
    },
  }
}

React + Dva

import {delay} from 'dva/saga'



debouncedCallEffect: [
  function* (action, { put }) {
    yield delay(1000);
    yield put({
      ...action,
      type: 'callEffect',
    });
  }, { type: "takeLatest" }
  // takeLatest 并不是纯粹意义的节流,只是响应最后一次结果
],
callEffect: [*function(action,{call}){
  const response = yield call(api)
}, {type: 'takeLatest'}],

节流 throttle

节流的原理: 如果你持续触发事件,每隔一段时间,只会执行一次事件

提交内容过多的后端处理时间较长的应做节流处理

Vue

export default {
  created() {
    this.throttleHandleSubmit = lodash.throttle(this.handleSubmit, 5000),
  },
  methods: {
    handleSubmit() {}
  },
}

React + Dva

// dva modal // 并且给button组件加loading  
// loading: loading.effects['nameSpace/callEffect'],
callEffect: [*function(action,{call}){
  const response = yield call(api)
  return response
}, {type: 'throttle', ms: 5000}]

校验

国产 UI 框架的 form 表单校验器大多基于async-validator,已经支持了众多校验模式和异步 Promise,熟读其文档很重要

// 自己实现简单校验方法
/**
 * vue中自己实现简单表单校验
 */
import { message } from 'ant-design-vue';
export default {
	install(Vue) {
		Vue.prototype.validateForm = function(validateArray) {
            console.log("validateArray=>",validateArray)
			let formArray = validateArray || Object.keys(this.formData);
			return !formArray.some((name) => {
				let rules = this.rules[name],
					inputValue = this.formData[name];
				if (!rules) {
					return false;
				}
				// 如果是必填字段
				if (rules.required && !inputValue) {
					message.error(rules.requiredMsg);
					return true;
				}

				// 如果是需要判断
				if (rules.validate) {
					if (!rules.validate.test(inputValue)) {
						message.error(rules.validateMsg);
						return true;
					}
				}
				return false;
			});
		};
	}
};
// 使用
// main.js中
Vue.use(validateForm);
// 业务页面当中
export default {
    name: "login",
    data() {
        return {
            formData: {
                userMobile: "",
                userPassword: "",
            },
            rules: {
                userMobile: {
                    required: true,
                    requiredMsg: "账号不能为空",
                    validate: /^1[3456789]\d{9}$/,
          			validateMsg: '手机号码格式错误'
                },
                userPassword: {
                    required: true,
                    requiredMsg: "密码不能为空",
                },
            },
        };
    },
     methods: {
     		login() {
     			  // 若单个使用可以传入参数this.validateForm(['userMobile']) 不传参数默认是校验全部
				  if (!this.validateForm()) {
		                return false;
	             }
			}
     }
}


ReactNative 中 表单校验一般都是自己写没有定制化需求,也可以使用以上方法

import Toast from './toast'
function validateForm (validateArray) {
    let formArray = validateArray|| Object.keys(this.formData) ;
    return !formArray.some( name => {
        let rules = this.state.rules[name],
            inputValue = this.state[name];
        if(!rules){
            return false;
        }
        // 如果是必填字段
        if (rules.required && !inputValue){
            Toast.show(rules.requiredMsg)
            return true;
        }

        // 如果是需要判断
        if (rules.validate){
            if(!rules.validate.test(inputValue)){
                Toast.show(rules.validateMsg)
                return true;
            }
        }
        return false;
    });
};
// 使用
import validateForm from 'utils/validateForm'; //引入
this.state={
    formData:{
		domainName:""
	},
	domainName: {
          required: true,
          requiredMsg: '请输入主域名',
          validate: /^1[3456789]\d{9}$/,
          validateMsg: '手机号码格式错误'
    },
}
// 验证 react native没有注入实例 此处需要使用call来改变this指向
if (!validateForm.call(this,['domainName'])) {
      return false;
}

react native表单防抖节流都可使用lodash插件绑定方法实现

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值