前端的Form 表单主要用于解决数据获取、数据校验、数据赋值 这三大类问题。我们设计组件的目标是为了极大的解决业务使用问题,使用便利性和可扩展性则是我们设计组件的最大目标!
这篇文章里面的提供的解决方案能够比较完美的用在 React 框架上,但是解决问题的思路相信应该是可以使用于任何框架语言。
中后台的表单组件已经不仅仅有 input 和 select,可能还扩展到 范围选择器、日期选择器 等,这些组件为了实现更优雅的UI和更便捷的交互往往会在原生的组件上面做多层封装,而经过多层叠加后可能已经看不到原生表单元素的影子了。比如经过封装下面这段 DOM 结构经过样式修改也可能成为一个输入组件,虽然完全看不到 input 的影子。
<span>
<span contentEditable></span>
</span>
所以为了便于大家理解我这里从传统的原生 form 说起,好让大家有一个递进的过程。
引子:原生 form 表单
最初始的一份代码如下,代码很简单,看着也很舒服。
<form action="/api/post" method="post">
username: <input name="username" />
password: <input name="password" />
<button type="submit">submit</button>
</form>
但是你开始做数据校验相关,表单就立刻变得复杂多了。如下:代码增多了一倍。
<script>
function checkname(target) {
const value = target.value;
if (value.length < 10) {
document.getElementById('username_msg').innerHTML = '长度必须>10'
} else {
document.getElementById('username_msg').innerHTML = ''
}
}
function checkpassword(target) {
const value = target.value;
if (!value.match(/^[w]{6,16}$/)) {
document.getElementById('password_msg').innerHTML = '密码必须 6-16 位字母数字'
} else {
document.getElementById('password_msg').innerHTML = ''
}
}
function getInitData() {
ajax({
url:'/api/data',
success:function(data) {
document.getElementById('username') = data.username;
});
}
getInitData();
</script>
<form action="/api/post" method="post">
username: <input name="username" onchange="checkname(this)"/>
<span id="username_msg"></span>
passowrd: <input name="password" onchange="checkpassword(this)"/>
<span id="password_msg"></span>
<button type="submit">submit</button>
</form>
如果把DOM的部分也用JS来实现,基本可以做到只修改JS不需要再动DOM结构,但是也让JS的复杂度增高不少。
React 里面所有的DOM结构都是自己通过JS 生成的,JSX也可以方便的实现DOM结构。但这里我拿原生表单举例,只是想说用 React 写出来的原生表单,并不比用原生 JS 的优雅多少!!!
React 中的原生 form 表单
同样一段最简单的功能,套在 react 框架下面是这个样子。
class Demo extends React.Component {
render() {
return <form action="/api/post" method="post">
username: <input name="username" />
passowrd: <input name="password" />
<button type="submit">submit</button>
</form>
}
}
比如同样想要实现校验输入自动校验 和 赋值,看下面一段代码,想想就是一大堆事情要做。
class Demo extends React.Component {
state = {
username: '',
password: '',
usernameMsg: '',
passwordMsg: '',
};
checkname = e => {
// 获取数据
const value = e.target.value;
// 受