# 表单
本章主要包含以下内容:
- 受控组件
- 非受控组件
## 受控组件
无论是学习 *Vue*,还是 *React*,最重要的是要转换思想,这一步非常重要,往往也比较困难。
在以前 *jQuery* 时代,开发人员需要获取到 *DOM* 节点,然后进行操作。而在现代前端开发中,采用的是 *MVVM* 的模式,将视图和视图模型进行绑定,视图模型的改变,会自然的带来视图的改变。开发人员需要专注在视图模型上面。
因此,这里所谓的受控组件,本质上其实就是将表单中的控件和视图模型(状态)进行绑定,之后都是针对状态进行操作。
下面,我们来看一些具体的案例:
- 一个基本的受控组件
```react
import React from "react";
// 类组件
class App extends React.Component {
state = {
value : ""
}
handleChange = (e) => {
this.setState({
value : e.target.value
})
}
clickHandle = () => {
// 提交整个表单
console.log(`你要提交的内容为:${this.state.value}`);
}
render() {
return (
)
}
}
export default App;
```
- 对用户输入的内容进行限制
```react
import React from "react";
// 类组件
class App extends React.Component {
state = {
value1 : "",
value2 : ""
}
handleChange = (e) => {
const name = e.target.name;
switch(name){
case "one": {
// 用户输入的是第一个输入框
// 只能输入大写
this.setState({
value1 : e.target.value.toUpperCase()
})
break;
}
case "two":{
// 用户输入的是第二个输入框
// 只能输入数字
const newValue = e.target.value.split("").map(item=>{
if(!isNaN(item)){
return item
}
}).join("");
this.setState({
value2 : newValue
})
break;
}
}
}
clickHandle = () => {
// 提交整个表单
console.log(`你要提交的内容为:${this.state.value}`);
}
render() {
return (
)
}
}
export default App;
```
- 文本域
```react
import React from "react";
// 类组件
class App extends React.Component {
state = {
value : ""
}
handleChange = (e) => {
this.setState({
value : e.target.value
})
}
clickHandle = () => {
// 提交整个表单
console.log(`你要提交的内容为:${this.state.value}`);
}
render() {
return (
)
}
}
export default App;
```
- 多选框
```react
import React from "react";
// 类组件
class App extends React.Component {
state = {
checkBoxs: [
{ content: "html", checked: false },
{ content: "css", checked: false },
{ content: "js", checked: false },
{ content: "vue", checked: false },
{ content: "react", checked: false },
],
}
handleChange = (index) => {
const arr = [...this.state.checkBoxs];
arr[index].checked = !arr[index].checked;
this.setState({
checkBoxs: arr
})
}
clickHandle = () => {
// 提交整个表单
console.log(this.state.checkBoxs);
}
render() {
return (
{
this.state.checkBoxs.map((item, index) => (
this.handleChange(index)}
/>
{item.content}
))
}
)
}
}
export default App;
```
- 下拉列表
```react
import React from "react";
// 类组件
class App extends React.Component {
state = {
value : "html"
}
handleChange = (e) => {
this.setState({
value : e.target.value
})
}
clickHandle = () => {
// 提交整个表单
console.log(this.state.value);
}
render() {
return (
)
}
}
export default App;
```
## 非受控组件
大多数情况下,在 *React* 中推荐使用受控组件来对表单进行操作,这样能够对表单控件的数据进行一个统一管理。
但是在某些特殊情况下,需要使用以前传统的 *DOM* 方案进行处理,此时替代的方案就是非受控组件。
- 非受控组件基本示例
```react
import React from "react";
// 类组件
class App extends React.Component {
constructor(){
super();
// 创建了一个 ref,回头我们就可以获取到和该 ref 绑定了的 DOM 节点
this.inputCon = React.createRef();
}
clickHandle = () => {
// 通过 this.inputCon.current 可以获取到 input DOM 节点
console.log(this.inputCon.current.value);
}
render() {
return (
)
}
}
export default App;
```
- 非受控组件的默认值
```react
{/* 一旦你用了 value,React 会认为你这是一个受控组件 */}
{/* 如果想要给默认值,使用 defaultValue */}
```
- 文件上传
```react
import React from "react";
// 类组件
class App extends React.Component {
constructor() {
super();
// 创建 ref 的时候,命名一般采用 xxxRef 结尾
this.uploadRef = React.createRef();
}
clickHandle = () => {
// 通过 this.uploadRef.current 可以获取到 input DOM 节点
console.log(this.uploadRef.current.files);
}
render() {
return (
)
}
}
export default App;
```
关于受控组件和非受控组件,可以参阅:*https://goshacmd.com/controlled-vs-uncontrolled-inputs-react/*