共计 15552 个字符,预计需要花费 39 分钟才能阅读完成。
React组件的核心理念就是可预知性和可测试性,给定同样的props和state,任何react组件都会渲染一样的结果。
表单状态属性
表单元素有这么几种属于状态的属性:
value
,对应<input>
和<textarea>
所有checked
,对应类型为checkbox
和radio
的<input>
所有
在 HTML 中 <textarea>
的值可以由子节点(文本)赋值,但是在 React 中,要用 value
来设置。
表单元素包含以上任意一种状态属性都支持 onChange
事件监听状态值的更改。
针对这些状态属性不同的处理策略,表单元素在 React 里面有两种表现形式:受控组件和非受控组件;
非受控组件
和受控组件相对,如果表单元素没有设置自己的“状态属性”,或者属性值设置为 null
,这时候就是非受控组件。
它的表现就符合普通的表单元素,正常响应用户的操作。
同样,你也可以绑定 onChange
事件处理交互。
如果你想要给“状态属性”设置默认值,
- 文本框和select使用defaultValue
- 单选框和复选框使用defaultChecked
如果要访问input的值需要设置ref属性即可。
var FormNo = React.createClass({
submitHandler:funcion(){
event.preventDefault();
var Hello = this.refs.Hello.getDOMNode().value;
console.log(Hello)
},
render:function(){
return(
<form onSubmit={this.submitHandler}>
<input ref="Hello" type="text" defaultValue = " hello,xxx"/>
<button type="submit">提交</button>
</form>
)
}
})
对于select,在 HTML 中 <select>
标签指定选中项都是通过对应 <option>
的 selected
属性来做的,但是在 React 修改成统一使用 value
。
<select value="B">
<option value="A">Apple</option>
<option value="B">Banana</option>
<option value="C">Cranberry</option>
</select>
你可以通过传递一个数组指定多个选中项:<select multiple={true} value={['B', 'C']}>
受控组件
一个受控的表单组件,它所有状态属性更改涉及 UI 的变更都由 React 来控制(状态属性绑定 UI)。输入的值一般都是由父组件控制的。
如果你希望输入的内容反馈到输入框,就要用 onChange
事件改变状态属性 value
的值:
getInitialState: function() {
return { value: 'hello'};
},
handleChange: function(event) {
//所有合成事件都提供了event.target来访问触发事件的DOM节点;例如
//var DomNode = event.target;
this.setState({value: event.target.value});
},
render: function() {
return (
<label htmlFor="name">Name:</label>
<input type="text" id="name" value={this.state.value} onChange={this.handleChange} />;
)
}
使用这种模式非常容易实现类似对用户输入的验证,或者对用户交互做额外的处理,比如截断最多输入140个字符:
handleChange: function(event) {
this.setState({value: event.target.value.substr(0, 140)});
}
对于受控组件中的select,获取select值的方法有两种:
- 通过表单合成事件(即自定义事件,驼峰命名法)event.target.value获取
handleChange:function(event){ this.setState({value:event.target.value}) }
- 循环检查DOM
handleChange:function(event){ var Checked = []; for(var i=0;i<event.target.length;i++){ var option = event.target.options[i]; if(option.selected){ Checked.push(option) } } this.setState({options:Checked }) }
关于表单中的name属性,对于非受控组件建议加上name,对于受控组件加或者不加都行;
多表单元素与change处理器:可以结合Mixin使用
- 使用.bind传递参数
- 使用DOMNode获取name属性值
这会在后面的自定义表单中举例说明;
Focus
React实现了autoFocus属性,在第一次挂载时通过设置该属性为true即可自动获取焦点。
表单可用性的原则
- 通过label或者placeholder把输入内容表达清楚
- 在失去焦点onblur,验证输入信息,不断反馈
- 使用过渡动画
- 要么遵循用户习惯,要么从根本上改变用户界面
- 可访问性:使用一种输入设备
- 减少用户输入:比如自动补全功能
自定义表单
栗子1:对于checkbox设置的state是对象时,这里使用同时使用name举例:
<script type="text/babel">
//对于checkbox设置的state是对象时,这里使用同时使用name举例:
var FromMixin = {
handleChange:function(text){
var newState ={};
var comonents = this;
return function(event){
if(text == 'Game'){
newState[text] = comonents.state[text] || {};
newState[text][event.target.id] = event.target.checked;
}else{
newState[text] = event.target.value;
};
comonents.setState(newState);
}
}
};
var FormReat = React.createClass({
mixins:[FromMixin],
getInitialState:function(){
return {
username:'',
password:'',
Game:{
LOL:false,
Dota:false,
WOW:false,
DNF:false
},
gender:'man',
city:'',
textarea:''
}
},
handleSumbit:function(event){
event.preventDefault();
event.stopPropagation();
console.log(this.state)
},
render:function(){
var divLabel = ['LOL','Dota','WOW','DNF'].map((item,i) => {
return (<div key={item}>
<label>{item}:</label>
<input type="checkbox" name="Game"
id={item}
checked={this.state.Game[{item}]}
onChange={this.handleChange('Game')} />
</div>)
}.bind(this))
return (
<form onSubmit={this.handleSumbit}>
<div>
<label>用户名:</label>
<input type="text" name="username" id="username" onChange={this.handleChange('username')}
value={this.state.name}/>
</div>
<br/>
<div>
<label>密 码:</label>
<input type="password" name="password" id="password" onChange={this.handleChange('password')}
value={this.state.password}/>
</div>
<br/>
<div>
<h4>性别</h4>
<label>男:</label>
<input type="radio" name="gender" id="man" value="man" checked={this.state.gender == "man" ? true : false}
onChange={this.handleChange('gender')}/>
<label>女:</label>
<input type="radio" name="gender" id="woman" value="woman" checked={this.state.gender == "woman" ? true : false}
onChange={this.handleChange('gender')}/>
</div>
<br/>
<div>
<label>城市:</label>
<select name="city" id="city" onChange={this.handleChange('city')}>
<option value="">请选择</option>
<option value="1">北京</option>
<option value="2">上海</option>
<option value="3">广州</option>
</select>
</div>
<br/>
<div>
<label>个人简介:</label>
<br/>
<textarea cols="40" rows="8" name="textarea" id="textarea" onChange={this.handleChange('textarea')}></textarea>
</div>
<br/>
<div>
<h4>喜欢的游戏</h4>
{divLabel}
</div>
<br/>
<div>
<input type="submit" value="Submit" />
</div>
</form>)
}
});
ReactDOM.render(<FormReat />, document.getElementById('app'));
</script>
栗子2:对于checkbox设置的state是数组时,这里使用同时使用.bind举例:
<script type="text/babel">
//对于checkbox设置的state是数组时,这里使用同时使用.bind举例:
var FormReat = React.createClass({
getInitialState:function(){
return {
username:'',
password:'',
Game:[],
gender:'man',
city:'',
textarea:''
}
},
handleChange:function(text,event){
var newState = {};
if(text == "Game"){
newState[text] = this.state.Game || [];
var d = newState[text].indexOf(event.target.id);
if(event.target.checked){
newState[text].push(event.target.id);
}else if(d != -1){
newState[text].splice(d,1)
};
}else{
newState[text] = event.target.value;
}
this.setState(newState);
},
handleSumbit:function(event){
event.preventDefault();
event.stopPropagation();
console.log(this.state)
},
render:function(){
return (<form onSubmit={this.handleSumbit}>
<div>
<label>用户名:</label>
<input type="text" name="username" id="username" onChange={this.handleChange.bind(this,'username')}
value={this.state.name}/>
</div>
<br/>
<div>
<label>密 码:</label>
<input type="password" name="password" id="password" onChange={this.handleChange.bind(this,'password')}
value={this.state.password}/>
</div>
<br/>
<div>
<h4>性别</h4>
<label>男:</label>
<input type="radio" name="gender" id="man" value="man" checked={this.state.gender == "man" ? true : false}
onChange={this.handleChange.bind(this,'gender')}/>
<label>女:</label>
<input type="radio" name="gender" id="woman" value="woman" checked={this.state.gender == "woman" ? true : false}
onChange={this.handleChange.bind(this,'gender')}/>
</div>
<br/>
<div>
<label>城市:</label>
<select name="city" id="city" onChange={this.handleChange.bind(this,'city')}>
<option value="">请选择</option>
<option value="1">北京</option>
<option value="2">上海</option>
<option value="3">广州</option>
</select>
</div>
<br/>
<div>
<label>个人简介:</label>
<br/>
<textarea cols="40" rows="8" name="textarea" id="textarea" onChange={this.handleChange.bind(this,'textarea')}></textarea>
</div>
<br/>
<div>
<h4>喜欢的游戏</h4>
<label>LOL:</label>
<input type="checkbox" id="LOL" checked={this.state.Game.indexOf('LOL') < 0 ? false : true} onChange={this.handleChange.bind(this,'Game')}/>
<label>Dota:</label>
<input type="checkbox" id="Dota" checked={this.state.Game.indexOf('Dota') < 0 ? false : true} onChange={this.handleChange.bind(this,'Game')}/>
<label>WOW:</label>
<input type="checkbox" id="WOW" checked={this.state.Game.indexOf('WOW') < 0 ? false : true} onChange={this.handleChange.bind(this,'Game')}/>
<label>DNF:</label>
<input type="checkbox" id="DNF" checked={this.state.Game.indexOf('DNF') < 0 ? false : true} onChange={this.handleChange.bind(this,'Game')}/>
</div>
<br/>
<div>
<input type="submit" value="Submit" />
</div>
</form>)
}
});
ReactDOM.render(<FormReat />, document.getElementById('app'));
</script>
栗子3:利用React.addons.LinkedStateMixin组件
<script src="../JS/react-0.14.7/build/react.js" type="text/javascript" charset="utf-8"></script>
<script src="../JS/react-0.14.7/build/react-dom.js" type="text/javascript" charset="utf-8"></script>
<script src="../JS/react-0.14.7/build/react-with-addons.js" type="text/javascript" charset="utf-8"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.24/browser.min.js"></script>
<script type="text/babel">
var FormReat = React.createClass({
mixins:[React.addons.LinkedStateMixin],
getInitialState:function(){
return {
username:'',
password:'',
Game:[],
gender:'man',
city:'',
textarea:''
}
},
handleChange:function(text,event){
var newState = {};
if(text == "Game"){
newState[text] = this.state.Game || [];
var d = newState[text].indexOf(event.target.id);
if(event.target.checked){
newState[text].push(event.target.id);
}else if(d != -1){
newState[text].splice(d,1)
};
}else{
newState[text] = event.target.value;
}
this.setState(newState);
},
handleSumbit:function(event){
event.preventDefault();
event.stopPropagation();
console.log(this.state)
},
render:function(){
return (<form onSubmit={this.handleSumbit}>
<div>
<label>用户名:</label>
<input type="text" name="username" id="username" valueLink = {this.linkState('username')}/>
</div>
<br/>
<div>
<label>密 码:</label>
<input type="password" name="password" id="password" valueLink = {this.linkState('password')}/>
</div>
<br/>
<div>
<h4>性别</h4>
<label>男:</label>
<input type="radio" name="gender" id="man" value="man" checked={this.state.gender == "man" ? true : false}
onChange={this.handleChange.bind(this,'gender')}/>
<label>女:</label>
<input type="radio" name="gender" id="woman" value="woman" checked={this.state.gender == "woman" ? true : false}
onChange={this.handleChange.bind(this,'gender')}/>
</div>
<br/>
<div>
<label>城市:</label>
<select name="city" id="city" valueLink = {this.linkState('city')}>
<option value="">请选择</option>
<option value="1">北京</option>
<option value="2">上海</option>
<option value="3">广州</option>
</select>
</div>
<br/>
<div>
<label>个人简介:</label>
<br/>
<textarea cols="40" rows="8" name="textarea" id="textarea" valueLink = {this.linkState('textarea')}></textarea>
</div>
<br/>
<div>
<h4>喜欢的游戏</h4>
<label>LOL:</label>
<input type="checkbox" id="LOL" checked={this.state.Game.indexOf('LOL') < 0 ? false : true} onChange={this.handleChange.bind(this,'Game')}/>
<label>Dota:</label>
<input type="checkbox" id="Dota" checked={this.state.Game.indexOf('Dota') < 0 ? false : true} onChange={this.handleChange.bind(this,'Game')}/>
<label>WOW:</label>
<input type="checkbox" id="WOW" checked={this.state.Game.indexOf('WOW') < 0 ? false : true} onChange={this.handleChange.bind(this,'Game')}/>
<label>DNF:</label>
<input type="checkbox" id="DNF" checked={this.state.Game.indexOf('DNF') < 0 ? false : true} onChange={this.handleChange.bind(this,'Game')}/>
</div>
<br/>
<div>
<input type="submit" value="Submit" />
</div>
</form>)
}
});
ReactDOM.render(<FormReat />, document.getElementById('app'));
</script>