写在开头:由于本人在写文章方面是新人,文章表述能力不足,所以从基础知识开始写起,本文太过基础,大佬不需要观看。
背景
在前端发展越来越快的今天,UI组件库已经非常成熟,项目开发中也离不开这些组件库,它们能帮助我们提高开发效率,统一开发规范。本文不介绍组件库,看看原生form表单有什么值得学习的地方。
React 中原生form
以React为例,我们在使用原生form时会这样写:
import { useState } from "react";
export default function App() {
const [name, setName] = useState("");
const [age, setAge] = useState("");
const [sex, setSex] = useState("");
const submitForm = async (e) => {
e.preventDefault();
const formData = {
name,
age,
sex
};
console.log('需要传给后端的数据', formData);
};
return (
<div className="App">
<form onSubmit={submitForm}>
<div>
<input
name="name"
value={name}
onChange={(e) => setName(e.target.value)}
placeholder="name"
/>
<div>{"sds"}</div>
</div>
<div>
<input
name="age"
value={age}
onChange={(e) => setAge(e.target.value)}
placeholder="age"
/>
</div>
<div>
<input
name="sex"
value={sex}
onChange={(e) => setSex(e.target.value)}
placeholder="sex"
/>
</div>
<br />
<button type="submit">Submit</button>
</form>
</div>
);
}
大家都知道这是受控组件的写法,我们一定需要受控组件吗?如果我只想单纯的提交表单呢。我们可以这样写:
import {useRef} from 'react'
export default function App() {
const nameRef = useRef('')
const ageRef = useRef('')
const sexRef = useRef('')
const submitForm = async (e) => {
e.preventDefault();
const formData = {
name: nameRef.current.value,
age: ageRef.current.value,
sex: sexRef.current.value
};
console.log('需要传给后端的数据', formData);
};
return (
<div className="App">
<form onSubmit={submitForm}>
<div>
<input
ref={nameRef}
name="name"
placeholder="name"
/>
<div>{"sds"}</div>
</div>
<div>
<input
ref={ageRef}
name="age"
placeholder="age"
/>
</div>
<div>
<input
ref={sexRef}
name="sex"
placeholder="sex"
/>
</div>
<br />
<button type="submit">Submit</button>
</form>
</div>
);
}
但是这样写声明了大量的ref,并不优雅。有没有其他办法获取到所有的表单值呢?
必须有!就是FormData对象。
FormData对象
语法:
let formData = new FormData(form);
参数:
一个 HTML 上的
表单元素——当指定了,这种方式创建的FormData对象会自动将 form 中的表单值也包含进去,包括文件内容也会被编码之后包含进去。所以我们可以formData对象获取所有的表单项的值,代码如下:
import { useState } from "react";
export default function App() {
const [name, setName] = useState("");
const [age, setAge] = useState("");
const submitForm = async (e) => {
e.preventDefault();
const formData = new FormData(e.target);
const dataObject = Object.fromEntries(formData);
console.log('需要传给后端的数据', dataObject); // {name: '', age: '', sex: ''}
};
return (
<div className="App">
<form onSubmit={submitForm}>
<div>
<input
name="name"
value={name}
onChange={(e) => setName(e.target.value)}
placeholder="name"
/>
<div>{"sds"}</div>
</div>
<div>
<input
name="age"
value={age}
onChange={(e) => setAge(e.target.value)}
placeholder="age"
/>
</div>
<br />
<button type="submit">Submit</button>
</form>
</div>
);
}
我们在受控和非受控组件中都可以轻松获取所有的表单项的值 ,当表单项过多时也不必一个一个去获取,非常方便。
有人说如果我想校验表单怎么办?
HTML的pattern属性 配合 css伪类:invalid 进行校验
还引用上述例子:
import { useState } from "react";
import "./styles.css";
export default function App() {
const [name, setName] = useState("");
const [age, setAge] = useState("");
const submitForm = async (e) => {
e.preventDefault();
const formData = new FormData(e.target);
const inputObject = Object.fromEntries(formData);
console.log(inputObject);
};
return (
<div className="App">
<form onSubmit={submitForm}>
<div>
<input
name="name"
pattern="[a-z]{3}" // 正则匹配校验
value={name}
onChange={(e) => setName(e.target.value)}
placeholder="name"
/>
<div>{"sds"}</div>
</div>
<div>
<input
name="age"
pattern="[0-9]{3}" // 正则匹配校验
value={age}
onChange={(e) => setAge(e.target.value)}
placeholder="age"
/>
</div>
<br />
<button type="submit">Submit</button>
</form>
</div>
);
}
css样式:
// styles.css
input:focus {
outline: none;
}
input:invalid {
border: red solid 3px;
}
效果如下: