在一個實際的項目中,表單是必不可少的DOM元素。項目中出現的表單元素,React要如何獲取用戶在表單元素中書寫或選擇的內容呢?本篇文章就爲你們講解React中受控組件的使用方法。
受控組件:Controlled Component,組件的數據受到state組件狀態的控制,咱們將這類組件稱爲「受控組件」。受控組件在使用時要實現組件數據和state組件狀態的雙向綁定。javascript
文本類表單元素包括文本域、密碼域、多行文本域三種表單元素。它們使用value屬性來綁定表單元素的默認值,同時使用onChange事件編寫當文本內容發生變化時所執行的代碼。咱們將這種用法稱爲「value-onChange」組合。html
例1:在頁面中有一個用於輸入暱稱的表單元素和一個按鈕。用戶在文本框中輸入本身的暱稱,單擊按鈕後獲取用戶輸入的暱稱內容,並在控制檯中顯示。
class App extends React.Component { constructor(props){ super(props); this.state={ nick:"" } } render(){ return ( <React.Fragment> <label htmlFor="nick">暱稱</label> <input type="text" id="nick" value={this.state.nick} onChange={(event)=>{this.nickChange(event)}} /> <div><button onClick={()=>this.getNick()}>獲取暱稱</button></div> </React.Fragment> ) } }
從上述代碼中能夠看出,文本框利用value屬性綁定了state區的nick數據做爲文本框的默認值,即空字符串。同時又爲文本框綁定了onChange事件。該事件只須要將文本框中用戶輸入的內容賦值給state區的nick數據便可。文本框中用戶輸入的內容可使用onChange事件函數中的event.tarvar.value獲取。前端
文本框的onChange事件代碼以下所示。java
onChange(event){ this.setState({ nick:event.target.value }) }
按鈕的單擊事件代碼以下所示。小程序
getNick(){ console.log(this.state.nick); }
從例1中能夠看出,文本框中的value屬性只能爲文本框綁定一個初始值,當文本框中的文本內容發生變化時,還須要藉助onChange事件來將文本框的值賦給value屬性當初綁定的state數據。微信小程序
例2:在頁面中有一個用於輸入留言的多行文本域和一個按鈕。用戶在多行文本框中輸入留言文本,單擊按鈕後獲取用戶輸入的留言內容,並在控制檯中顯示。同時隨着用戶輸入文本的增多,在頁面中顯示已經輸入了多少個字符,同時限制最多輸入20個字符。
效果圖以下所示。數組
class App extends React.Component { constructor(props){ super(props); this.state={ message:"", inputed:0, total:20 } } render(){ return ( <React.Fragment> <label htmlFor="message">留言:(已輸入{this.state.inputed}/{this.state.total})</label> <textarea id="message" value={this.state.message} onChange={(event)=>{this.messageChange(event)}></textarea> <div><button onClick={()=>this.submitMessage()}>提交留言</button></div> </React.Fragment> ) } }
多行文本域的處理方式和文本域的處理方式相同,都是採用value-onChange組合來實現的。當用戶在多行文本域中輸入內容時,將觸發onChange事件,該事件代碼以下所示。微信
messageChange(event){ let message=event.target.value; this.setState({ inputed:message.length }) if(this.state.inputed<this.state.total-1){ this.setState({ message }) } }
按鈕的單擊事件代碼以下所示。函數
submitMessage(){ console.log(this.state.message); }
在state區中,message數據用來接收用戶在多行文本域中輸入的內容,inputed數據用來記錄已經輸入的文本個數,total數據用來指定最多可以輸入的文本個數。大數據
單選框在使用時繼續延續文本框和多行文本框的使用方式,惟一不一樣的是單選框採用的是checked-onChange組合來實現受控操做的。
例3:在頁面中有一組用於選擇性別的單選框和一個按鈕。用戶選擇了某個單選項以後,單擊按鈕獲取用戶所選單選項的內容,並在控制檯中顯示。
class App extends Component{ constructor(props){ super(props); this.state={ sex:'男' } } render(){ return ( <React.Fragment> <label>性別:</label> <input type="radio" value="男" checked={this.state.sex==="男"} onChange={(event)=>this.radioChange(event)} /> 男 <input type="radio" value="女" checked={this.state.sex==="女"} onChange={(event)=>this.radioChange(event)} /> 女 <div><button onClick={()=>this.getSex()}>所選性別</button></div> </React.Fragment> ) } }
在上述代碼中,每個單選框一樣具有了value屬性,可是這個value屬性已經和文本框的value屬性不同了,這個value屬性爲單選框被選中後提供了與其餘單選框所不一樣的數據。checked屬性取值爲邏輯值,所以綁定的是this.state.sex是否是和指定的取值相等,相等則爲true,不相等則爲false。
單選框的onChange事件代碼以下所示。
radioChange(event){ this.setState({ sex:event.target.value }) }
按鈕的單擊事件代碼以下所示。
getSex(){ console.log(this.state.sex); }
代碼中經過checked屬性中的判斷來獲取哪個單選項默認被選中,再借助onChange事件改變state區的sex數據,以實現checked屬性和sex數據的雙向綁定。
複選框和單選框同樣,也是用checked-onChange組合來對其進行操做,可是複選框能夠選中多個複選項,而單選框只能選擇一個,所以複選框的checked屬性一應該綁定的是一個數組。
例4:在頁面中有一組用於選擇愛好的複選框和一個按鈕。用戶選擇了某些複選項以後,單擊按鈕獲取用戶所選複選項的內容,並在控制檯中顯示。
效果圖以下所示。
class App extends Component{ constructor(props){ super(props); this.state={ favs:["音樂","電影","遊戲","跑步","游泳","讀書"], fav:["電影"] } } render(){ return ( <React.Fragment> <label>愛好:</label> { this.state.favs.map((item,index)=>{ return ( <span key={index}> <input type="checkbox" value={item} checked={this.state.fav.includes(item)} onChange={(event)=>this.checkboxChange(event)} /> {item} </span> ) }) } <div><button onClick={()=>this.getFav()}>所選愛好</button></div> </React.Fragment> ) } }
在上述代碼中,state區定義了兩個數據:favs做爲數組提供全部備選的愛好內容,fav做爲數組用來存儲用戶選擇的愛好內容。
複選框的onChange事件代碼以下所示。
checkboxChange(event){ let temp=event.target.value; //用戶選中的那一個複選框的value屬性 let fav=[...this.state.fav]; let index=fav.findIndex(item=>item===temp); if(index!==-1){ //單擊該複選框時,該複選框的value屬性取值在fav數組中存在 fav.splice(index,1); }else{ //單擊該複選框時,該複選框的value屬性取值在fav數組中不存在 fav.push(temp); } this.setState({fav}); }
按鈕的單擊事件代碼以下所示。
getFav(){ console.log(this.state.fav) }
該案例涉及到了大量的數組與數組元素之間的操做。雖然一樣使用checked-onChange組合來完成,可是兩個數組favs和fav之間要進行大量的判斷,才能完成最終的效果。
<select>菜單在表單元素中表示下拉菜單,是一個單選元素,一樣使用value-onChange組合來進行處理。
例5:在頁面中有一組用於選擇專業的下拉菜單和一個按鈕。用戶選擇了某個專業以後,單擊按鈕獲取用戶所選專業的內容,並在控制檯中顯示。
class App extends Component{ constructor(props){ super(props); this.state={ specs:["前端開發","PHP開發","Java開發","UI設計","大數據開發","人工智能"], spec:"前端開發" } } render(){ return ( <React.Fragment> <label>專業:</label> <select value={this.state.spec} onChange={(event)=>this.specChange(event)}> { this.state.specs.map((item,index)=>{ return <option value={item} key={index}>{item}</option> }) } </select> <div><button onClick={()=>this.getSpec()}>所選專業</button></div> </React.Fragment> ) } }
在上述代碼中,state區定義了兩個數據:specs做爲數組提供全部備選的專業內容,spec用來存儲用戶選擇的專業內容,由於是單選,所以數據類型爲字符串。
下拉菜單的onChange事件代碼以下所示。
specChange(event){ this.setState({ spec:event.target.value }) }
按鈕的單擊事件代碼以下所示。
getSpec(){ console.log(this.state.spec) }
仔細分析,下拉菜單的處理方式本質上和文本框是徹底相同的。
<select>列表在表單元素中表示列表選擇框,是一個能夠複選的元素,一樣使用value-onChange組合來進行處理。
例6:在頁面中有一組用於選擇選修課程的下拉列表和一個按鈕。用戶選擇了某些選修課程後,單擊按鈕獲取用戶所選的選修課程內容,並在控制檯中顯示。
效果圖以下所示。
class App extends Component{ constructor(props){ super(props); this.state={ courses:["高等數學","線性代數","機率統計","離散數學","複變函數與積分變換","關係代數"], course:[] } } render(){ return ( <React.Fragment> <label>選修:</label> <select value={this.state.course} onChange={(event)=>this.courseChange(event)} multiple size={this.state.courses.length}> { this.state.courses.map((item,index)=>{ return <option key={index} value={item}> {item} </option> }) } </select> <div><button onClick={()=>this.getCourse()}>所選選修課</button></div> </React.Fragment> ) } }
在上述代碼中,state區定義了兩個數據:courses做爲數組提供全部備選的選修課程內容,course用來存儲用戶選擇的選修課程內容,由於是多選,所以數據類型爲數組。
這裏提供兩種不一樣的機制來完成<select>標記的onChange事件。
courseChange(event){ let value=event.target.value; let course=[...this.state.course]; // 判斷value值是否在course數組中出現過 let index=course.findIndex(item=>item===value); if(index>=0){ course.splice(index,1); }else{ course.push(value); } this.setState({course}); }
courseChange(event){ let options=event.target.options; let temp=[]; //盛放被選中的option項的索引值的數組 for(let i in options){ if(options[i].selected){ temp.push(i); } } let course=temp.map(item=>options[item].value); this.setState({course}); }
上述原理造成的代碼能夠簡化爲如下ES6代碼:
let options=event.target.options; let course=Object.keys(options).filter(item=>options[item].selected===true).map(item=>options[item].value); this.setState({course});
本文是React系列教程的第六篇文章,主要爲你們講解了React表單元素的受控組件操做。文本框、密碼域、多行文本域、select列表、select菜單都是採用value-onChange組合來實現受控操做的。單選框、複選框是採用checked-onChange組合來實現受控操做的。同時具備複選功能的複選框和列表須要藉助數組來接收用戶所選的內容,操做起來較爲複雜。明天會爲你們系統的講解React中非受控表單元素的使用方法。
小海前端,具備18年Web項目開發和先後臺培訓經驗,在前端領域著有較爲系統的培訓教材,對Vue.js、微信小程序開發、uniApp、React等全棧開發領域都有較爲深的造詣。入住Segmentfault,但願可以更多的結識Web開發領域的同仁,將Web開發大力的進行普及。同時也願意與你們進行深刻的技術研討和商業合做。