364 lines
7.2 KiB
Markdown
364 lines
7.2 KiB
Markdown
# 表单
|
||
|
||
本章主要包含以下内容:
|
||
|
||
- 受控组件
|
||
- 非受控组件
|
||
|
||
|
||
|
||
## 受控组件
|
||
|
||
无论是学习 *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 (
|
||
<div>
|
||
<input type="text" value={this.state.value} onChange={this.handleChange}/>
|
||
<button onClick={this.clickHandle}>提交</button>
|
||
</div>
|
||
)
|
||
}
|
||
|
||
}
|
||
|
||
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 (
|
||
<div>
|
||
<input
|
||
type="text"
|
||
name="one"
|
||
value={this.state.value1}
|
||
onChange={this.handleChange}
|
||
placeholder="自动转为大写"
|
||
/>
|
||
<input
|
||
type="text"
|
||
name="two"
|
||
value={this.state.value2}
|
||
onChange={this.handleChange}
|
||
placeholder="只能输入数字"
|
||
/>
|
||
<button onClick={this.clickHandle}>提交</button>
|
||
</div>
|
||
)
|
||
}
|
||
|
||
}
|
||
|
||
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 (
|
||
<div>
|
||
<textarea
|
||
cols="30"
|
||
rows="10"
|
||
value={this.state.value}
|
||
onChange={this.handleChange}
|
||
/>
|
||
<button onClick={this.clickHandle}>提交</button>
|
||
</div>
|
||
)
|
||
}
|
||
|
||
}
|
||
|
||
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 (
|
||
<div>
|
||
<div>
|
||
{
|
||
this.state.checkBoxs.map((item, index) => (
|
||
<div key={index}>
|
||
<input
|
||
type="checkbox"
|
||
value={item.content}
|
||
checked={item.checked}
|
||
onChange={()=>this.handleChange(index)}
|
||
/>
|
||
<span>{item.content}</span>
|
||
</div>
|
||
))
|
||
}
|
||
</div>
|
||
<button onClick={this.clickHandle}>提交</button>
|
||
</div>
|
||
)
|
||
}
|
||
|
||
}
|
||
|
||
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 (
|
||
<div>
|
||
<select value={this.state.value} onChange={this.handleChange}>
|
||
<option value="html">HTML</option>
|
||
<option value="css">CSS</option>
|
||
<option value="js">JS</option>
|
||
<option value="vue">Vue</option>
|
||
<option value="react">React</option>
|
||
</select>
|
||
<button onClick={this.clickHandle}>提交</button>
|
||
</div>
|
||
)
|
||
}
|
||
|
||
}
|
||
|
||
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 (
|
||
<div>
|
||
<input type="text" ref={this.inputCon}/>
|
||
<button onClick={this.clickHandle}>获取用户输入的内容</button>
|
||
</div>
|
||
)
|
||
}
|
||
|
||
}
|
||
|
||
export default App;
|
||
|
||
```
|
||
|
||
- 非受控组件的默认值
|
||
|
||
```react
|
||
<div>
|
||
{/* 一旦你用了 value,React 会认为你这是一个受控组件 */}
|
||
{/* 如果想要给默认值,使用 defaultValue */}
|
||
<input type="text" ref={this.inputCon} defaultValue="123"/>
|
||
<button onClick={this.clickHandle}>获取用户输入的内容</button>
|
||
</div>
|
||
```
|
||
|
||
- 文件上传
|
||
|
||
```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 (
|
||
<div>
|
||
<input type="file" ref={this.uploadRef}/>
|
||
<button onClick={this.clickHandle}>获取用户输入的内容</button>
|
||
</div>
|
||
)
|
||
}
|
||
|
||
}
|
||
|
||
export default App;
|
||
|
||
```
|
||
|
||
|
||
|
||
关于受控组件和非受控组件,可以参阅:*https://goshacmd.com/controlled-vs-uncontrolled-inputs-react/*
|
||
|