16、表单
总结写前面
值的改变,通过 onChange 事件触发(包括文字输入框、radio、checkbox);
选中与否,通过设置 HTML 元素的 checked 等于一个符合要求的 state 的值(因此表达式结果为 true,于是 checked='true' 就是选中),来实现。
【form】标签:
如果用 form 标签的话,在通过 submit 按钮提交时,会自动触发页面跳转,但这个通常是我们不需要的;
解决办法是,添加 onSubmit 事件,如:<form onSubmit={this.submit}>,在这个函数里,通过 e.preventDefault() 阻止默认的提交行为,
示例代码:
class HelloWord extends React.Component {
constructor(props) {
super(props);
this.state = {
name: ''
}
this.submit = this.submit.bind(this)
}
render() {
return <form onSubmit={this.submit}>
<label>
male
<input type="radio" name='gender' value='male'/>
</label>
<label>
female
<input type="radio" name='gender' value='female'/>
</label>
<input type="submit"/>
</form>
}
submit(e) {
console.log(arguments)
e.preventDefault();
}
}
【input[type=text]】标签:
默认情况下,通过 value=this.state.xxx 绑定,是单向绑定。即改变 state 存储的值,可以自动修改 input 的值,但是用户修改 input 的值,是无法修改成功的。
用户想要输入值,必须设置 onChange 事件才可以,这样才能实现 双向绑定。
示例代码:
class HelloWord extends React.Component {
constructor(props) {
super(props);
this.state = {
value: ''
}
this.valueChange = this.valueChange.bind(this)
}
render() {
return <form onSubmit={this.submit}>
<input type="text" value={this.state.value} onChange={this.valueChange}/>
<br/>
输入框的值:{this.state.value}
</form>
}
valueChange(e) {
this.setState({
value: e.target.value
})
}
}
【textarea】标签:
使用方法等同 input[type=text],略。
【input[type=radio]】标签:
注意,radio 以及 checkbox 的 value 设置和一般不同。
原因在于,radio 的 value 属性,表示当你选中这个单选框时,这个单选框的值,当你需要表示我选中这个单选框,那么应该通过 checked = true|'check' 来实现选中。
示例代码:
class HelloWord extends React.Component {
constructor(props) {
super(props);
this.state = {
gender: 'male'
}
this.select = this.select.bind(this)
}
render() {
return <form>
<label>
male
{/* 可以返回 true 表示选中 */}
<input type="radio" name='gender' value='male'
checked={this.state.gender === 'male'}
onChange={this.select}/>
</label>
<label>
female
{/* 也可以返回checked 表示选中 */}
<input type="radio" name='gender' value='female'
checked={this.state.gender === 'female' ? 'checked' : ''}
onChange={this.select}/>
</label>
<br/>
你当前选择的性别是:{this.state.gender}
</form>
}
select(e) {
this.setState({
gender: e.target.value
})
}
}
【input[type=checkbox]】标签:
这个显然就更麻烦了。他表现 选中/未选中 状态,和 radio 是一样的。
但问题在于,checkbox 在一个 name 属性下可能有多个变量,
所以你需要用数组来存储当前选中的 checkbox 有谁,
例如:gender: ['male', 'female'],
然后通过 indexOf(xx) > -1 来判断存在不存在(-1 表示不存在)。
示例代码:
class HelloWord extends React.Component {
constructor(props) {
super(props);
this.state = {
gender: ['male', 'female']
}
this.select = this.select.bind(this)
}
render() {
return <form>
<label>
male
{/* 可以返回 true 表示选中 */}
<input type="checkbox" name='gender' value='male'
checked={this.state.gender.indexOf('male') > -1}
onChange={this.select}/>
</label>
<label>
female
{/* 也可以返回checked 表示选中 */}
<input type="checkbox" name='gender' value='female'
checked={this.state.gender.indexOf('female') > -1}
onChange={this.select}/>
</label>
<br/>
你当前选择的性别是:{this.state.gender.join(',')}
</form>
}
select(e) {
// 先拿到值和索引
let v = e.target.value
let i = this.state.gender.indexOf(v)
// 有则移除,无则添加
if (i === -1) {
this.state.gender.push(v)
} else {
this.state.gender.splice(i, 1)
}
// 最后必须setState设置一下,才会触发render
this.setState({
gender: this.state.gender
})
}
}
当然,也可以通过 对象 的方式来存储,写的话更简单,只不过取用数据的时候,可能会麻烦一些,如示例:
class HelloWord extends React.Component {
constructor(props) {
super(props);
this.state = {
gender: {
male: false,
female: false
}
}
this.select = this.select.bind(this)
}
render() {
return <form>
<label>
male
<input type="checkbox" name='gender' value='male'
checked={this.state.gender.male}
onChange={this.select}/>
</label>
<label>
female
<input type="checkbox" name='gender' value='female'
checked={this.state.gender.female}
onChange={this.select}/>
</label>
<br/>
你当前选择的性别是:{JSON.stringify(this.state.gender)}
</form>
}
// 以下这种写法是可复用写法(即多个不同的 checkbox 可以复用这一个函数)
select(e) {
let v = e.target.value
let name = e.target.name
this.state[name][v] = !this.state[name][v]
this.setState({
[name]: this.state[name]
})
}
}
【select】标签:
select 标签在使用的时候,和 Vue 有一点最大的不同之处在于:
当 Vue 中设置 select 标签的值为 空字符串 时,那么 select 标签会不选中任何 option;
当 React 中设置 select 标签的值为 空字符串3 时,那么 select 标签会默认选中 第一个 option 标签 ;
不管将 select 标签绑定的 value 的值设置为 空字符串 ,或者是 null,或者是 option 标签不存在的值,React 都会将 select 标签绑定的 value 的值设置为 空字符串;
然后由于当 select 标签绑定的值为空字符串时,会在 页面视觉 上,默认选中第一个 option 标签;
如果你此时去拿select的值,拿到的是空字符串;但是通过select标签来拿值,那么拿到的是第一个 option 的值;
也就是说,当值为 空字符串 时,页面上显示的效果,和实际值不同!
所以需要通过 js 手动将该 DOM 标签的值设置为空字符串,才可以。
具体解决办法如下(包含 select 标签使用方法):
class HelloWord extends React.Component {
constructor(props) {
super(props);
this.state = {
gender: ''
}
this.select = this.select.bind(this)
}
render() {
return <p>
<select value={this.state.gender} ref={input => {
this.DOM = input
}} onChange={this.select} id='abc'>
<option value="male">male</option>
<option value="female">female</option>
</select>
<br/>
你当前选择的性别是:{this.state.gender}
<button onClick={this.setGender.bind(this)}>点击不设置gender</button>
</p>
}
// 以下这种写法是通用写法
select(e) {
let v = e.target.value
this.setState({
gender: v
})
}
setGender() {
this.setState({
gender: ''
})
}
// 如果假如 select 为空的话,需要通过 ref 手动拿到元素,然后设置 value 的值为空,从而默认不选择值
componentDidUpdate(preProps, preState) {
console.log('componentDidUpdate', arguments)
if (this.state.gender === '') {
this.DOM.value = ''
}
}
// 如果初始为空的话,也需要在这里手动配置一波,这是组件创建时【生命周期】在挂载完毕时执行的函数
componentDidMount() {
console.log('componentDidMount')
if (this.state.gender === '') {
this.DOM.value = ''
}
}
}