好久好久之前,就有人用CSS來時給HTML內容添加樣式。CSS能夠最大限度的分離樣式和內容,選擇器也能夠很方便的給某些元素添加樣式。你根本找不到任何不用CSS的理由。javascript
可是在React這裏就是另一回事了,雖然React不是不用CSS。可是,它在給元素添加樣式的時候方式不一樣。React的核心哲學之一就是讓可視化的組件自包含,而且可複用。這就是爲何HTML元素和Javascript放在一塊兒組成了Component
(組件)。css
React的自包含組件須要在定義的時候就定義好樣式,這樣才能實現自包含。本文即將帶你學習如何給React的組件添加樣式,固然其中包括如何使用CSS。兩個都會講到,雖然React不鼓勵這樣。html
要在HTML也中使用React有兩種方法,一個是使用Webpack編譯打包,另外一個是使用網頁直接添加React相關js文件。java
用webpack來編譯、打包React組件。並在一個index.html的頁面中使用該代碼。具體的準備步驟能夠看這裏。最後打包到一個叫作bundle.js的文件中。HTML頁面看起來是這樣的:react
<html> <head> <meta charset="utf-8"> <title>Add style to React</title> </head> <body> <div id="content" /> <script src="public/bundle.js" type="text/javascript"></script> <span style="float:center">Yo!</span> </body> </html>
也能夠在網頁中直接使用React的js代碼。jquery
<html> <head> <meta charset="utf-8"> <title>Add style to React</title> <!-- 所須要引入的React及相關js --> <script src="https://npmcdn.com/react@15.3.1/dist/react.js"></script> <script src="https://npmcdn.com/react-dom@15.3.1/dist/react-dom.js"></script> <script src="https://npmcdn.com/babel-core@5.8.38/browser.min.js"></script> <script src="https://npmcdn.com/jquery@3.1.0/dist/jquery.min.js"></script> <!-- end --> </head> <body> <div id="content" /> <!-- 咱們本身的js --> <script src="public/bundle.js" type="text/javascript"></script> <span style="float:center">Yo!</span> </body> </html>
jquery文件能夠不用添加,這裏用jquery是用來請求服務器的,暫時用不到。webpack
不管使用哪種方式。最後在頁面中使用的js都是bundle.js。若是用了webpack的方式,那麼bundle.js就是由webpack便已打包生成的。若是用的第二種方法,那麼bundle.js就是咱們本身手動編寫的js代碼。web
<div id="content" />
React生成的HTML元素都會放在這個div
裏面。ajax
使用Webpack的話,項目的總體結果是這樣的:npm
-webapp |--public // webpack 編譯打包後的js文件所在目錄 |--css // css文件所在的目錄 |--src // 使用React編寫的代碼所在目錄 |--index.html // HTML頁面
若是你使用網頁內部加載React的話,那麼就直接在public目錄下建立一個bundle.js文件,並在index.html引用便可。
咱們就以一個用戶登陸的界面喂例子。登陸,用戶需呀輸入用戶名、密碼,而後點擊登陸按鈕。
咱們來看看要實現這個功能React代碼應該什麼樣的。
import React from 'react'; import {render} from 'react-dom'; import LabeledInputText from './LabeledInputText'; import SubmitButton from './SubmitButton'; class App extends React.Component { constructor(props) { super(props); this.state = {un: '', pwd: ''}; this.handleLogin = this.handleLogin.bind(this); this.handleUserNameChanged = this.handleUserNameChanged.bind(this); this.handlePasswordChanged = this.handlePasswordChanged.bind(this); } handleUserNameChanged(un) { this.setState({un: un}); } handlePasswordChanged(pwd) { this.setState({pwd: pwd}); } handleLogin() { // $.ajax({ // url: this.props.url, // dataType: 'json', // method: 'POST', // data: this.state, // cache: false, // success: function(data) { // this.setState({data: data}); // }.bind(this), // error: function(xhr, status, err) { // console.error(this.props.url, status, err.toString()); // }.bind(this) // }); alert(`${this.state.un}, ${this.state.pwd}`); } render() { var divStyle = { color: 'blue', wdith: '150px', paddingTop: '10px', display: 'inline-block' }; return ( <div style={divStyle}> <p> Yo, React </p> <LabeledInputText labelText="Username" onUserNameChanged={this.handleUserNameChanged} /> <LabeledInputText labelText="Password" onPasswordChanged={this.handlePasswordChanged} /> <SubmitButton title="Submit" onLogin={this.handleLogin} /> </div> ); } } render(<App />, document.getElementById('content')); // LabeledInputText import React from 'react'; export default class LabeledInputText extends React.Component { constructor(props) { super(props); this.handleTextChange = this.handleTextChange.bind(this); } handleTextChange(e) { if (this.props.labelText.toLowerCase() == 'username') { this.props.onUserNameChanged(e.target.value); } else { this.props.onPasswordChanged(e.target.value); } } render() { return ( <div> <span>{`${this.props.labelText} :`}</span> <input type="text" placeholder={this.props.labelText} onChange={this.handleTextChange} /> </div> ); } } // SubmitButton import React from 'react'; export default class SubmitButton extends React.Component { constructor(props) { super(props); // this.state = {value: ''}; // bind event handler this.handleLogin = this.handleLogin.bind(this); } handleLogin(e) { // this.setState({value: e.target.value}); // alert('hello react'); this.props.onLogin() } render() { return ( <input onClick={this.handleLogin} type="button" value={this.props.title} /> ); } }
App
類是這個登陸界面的總體。裏面的HTML元素能夠分爲兩類,一個是label和label後面的輸入框,另外一類是提交按鈕。
LabeledInputText
是label和輸入框的組合。SubmitButton
是提交按鈕。
生成出來的HTML頁面是這樣的:
<html><head> <meta charset="utf-8"> <title>Add style to React</title> </head> <body> <div id="content"> <p> Yo, React </p> <div> <div> <span>Username :</span> <input type="text" placeholder="Username"> </div> <div> <span>Password :</span> <input type="text" placeholder="Password"> </div> <input type="button" value="Submit"> </div> </div> </body> </html>
在添加樣式以後,效果是這樣的:
在React組件上使用CSS樣式比你想的還要簡單。由於最終React仍是把組件都轉化成了HTML元素,而你會的各類CSS技巧同樣均可以做用在這些元素上。可是仍是有一些小小的地方須要注意:
在使用CSS以前,你須要知道React生成的HTML元素是什麼樣子的。看起來很容易理解,由於JSX語法和HTML元素很是接近。
import React from 'react'; import {render} from 'react-dom'; import LabeledInputText from './LabeledInputText'; import SubmitButton from './SubmitButton'; class App extends React.Component { constructor(props) { super(props); this.state = {un: '', pwd: ''}; } render() { var divStyle = { color: 'blue', wdith: '150px', paddingTop: '10px', display: 'inline-block' }; return ( // <div style={divStyle}> <div className="box-group"> {/*<p> Yo, React </p>*/} <LabeledInputText labelText="Username" onUserNameChanged={this.handleUserNameChanged} /> <LabeledInputText labelText="Password" onPasswordChanged={this.handlePasswordChanged} /> <SubmitButton title="Click" onLogin={this.handleLogin} /> </div> ); } } render(<App />, document.getElementById('content'));
在render
方法裏的就是總體的React組件的結構。全部的東西都在一個div裏面。LabeledInputText
就是一個文字Label和一個input的文本輸入框的組合。SubmitButton
是一個能夠點擊的按鈕,這裏實際上是一個含有click事件的div。
所有組件生成HTML以後:
<div id="content"> <div data-reactroot="" class="box-group"> <div class="form-control"> <span>Username :</span><input type="text" placeholder="Username"> </div> <div class="form-control form-under"> <span>Password :</span><input type="text" placeholder="Password"> </div> <div class="form-control form-under form-button"> Click </div> </div> </div>
裏面一些div包含的各類元素,就如前文所說的同樣。另外還有的就是不少的css的class。
首先添加css樣式文件:
input:focus{ outline: none !important; border:1px solid red; /*box-shadow: 0 0 10px #719ECE;*/ } .box-group { width:230px; border: 1px solid blue; padding:5px; margin: 10px; } .form-control { padding:5px; } .form-under { margin-top:10px; } .form-button { display:block; background-color:red; text-align: center; }
上面就是main.css文件包含的所有的樣式。這些樣式主要是給登陸的整個界面元素的邊框設置爲藍色,而後在用戶名、密碼和登陸按鈕之間增長間距,最後給按鈕指定背景色爲紅色。
接下來須要在React的組件中使用這些樣式。可是直接使用class是不行的。畢竟JSX和HTML元素是有區別的。就以登陸按鈕爲例:
<div onClick={this.handleLogin} className="form-control form-under form-button"> {this.props.title} </div>
在React中指定class名稱使用className
。React的className
最後就會轉化成HTML的class
。
這個登陸按鈕的樣式有一點複雜:className="form-control form-under form-button"
使用了三個不一樣的css的selector。這些selector的樣式都會應用到這個登陸按鈕上。
React推崇的是內聯的方式定義樣式。這樣作的目的就在於讓你的組件更加的容易複用。和組件相關的所有內容聚合到一塊兒,包括你的組件看起來是什麼樣的,是如何工做的。
下面就把以前添加的所有的樣式className
都去掉,回到最開始的狀態。
/* index.js */ <div> {/*<p> Yo, React </p>*/} <LabeledInputText labelText="Username" onUserNameChanged={this.handleUserNameChanged} /> <LabeledInputText labelText="Password" onPasswordChanged={this.handlePasswordChanged} /> <SubmitButton title="Click" onLogin={this.handleLogin} /> </div> /*LabeledInputText*/ <div> <span>{`${this.props.labelText} :`}</span> <input type="text" placeholder={this.props.labelText} onChange={this.handleTextChange} /> </div> /*SubmitButton*/ <div onClick={this.handleLogin}> {this.props.title} </div>
登陸使用的三個組件的render
方法返回的內容的className
已經所有都去掉了。
要往React組件內添加一個自定義的樣式對象,這個對象包含的就是css樣式的名稱和樣式的值。只不過樣式的名稱不是css的background-color
而是JSX的backgroundColor
。例如:
let divStyle = { width:'230px', border: '1px solid blue', padding:'5px', margin: '10px' }; return ( <div style={divStyle}> {/*<p> Yo, React </p>*/} <LabeledInputText labelText="Username" onUserNameChanged={this.handleUserNameChanged} /> <LabeledInputText labelText="Password" onPasswordChanged={this.handlePasswordChanged} /> <SubmitButton title="Click" onLogin={this.handleLogin} /> </div> );
小貼士
在React裏註釋不能用HTML的方式,那是木有用的。也不能直接用js的 註釋,那也是不行的。而是用大括號括起來,以後用/**/來註釋。 看起來是這樣的`{/* 這是一個註釋 */}`。
divStyle
就是咱們定義的樣式對象。要使用這個樣式,只要在React組件中給style
賦值。如:style={divStyle}
。
要讓組件的子組件的某些樣式能夠自定義很簡單。只須要使用React組件的props
。好比,我如今想要定製不一樣的用戶名、密碼輸入框的邊框顏色。
<div style={divStyle}> {/*<p> Yo, React </p>*/} <LabeledInputText labelText="Username" bordercolor="green" onUserNameChanged={this.handleUserNameChanged} /> <LabeledInputText labelText="Password" bordercolor="red" onPasswordChanged={this.handlePasswordChanged} /> <SubmitButton title="Click" onLogin={this.handleLogin} /> </div>
以後在LabeledInputText
文件中:
styleObj = Object.assign({}, this.pwdStyle, {border: '1px solid ' + this.props.bordercolor});
每次須要用到邊框值的時候都從props裏面取:this.props.bordercolor
。
HTML的文本輸入框有兩種狀態,focused和blured。用戶要輸入內容的時候,文本框就在focus的狀態下。用戶的焦點移開,好比開始輸入密碼的時候,用戶名的文本框就在blur狀態下了。
在focus的狀態下的時候,顯示指定顏色的邊框,不然不顯示邊框。這個時候就要用到React的另外一個重要概念:State
。
首先,給input註冊focus和blur的事件處理方法。
<input type="text" ref="theInput" placeholder={this.props.labelText} style={this.getInputStyles()} onChange={this.handleTextChange} onFocus={this.handleFocus} onBlur={this.handleBlur} /> // hanleFocus & handleBlur handleFocus() { this.setState({focused: true}); } handleBlur() { this.setState({focused: false}); }
狀態都存在state
裏了。而後在input裏指定style:style={this.getInputStyles()}
。getInputStyles
方法就會根據不一樣的狀態返回不一樣的樣式。
getInputStyles() { let styleObj; if (this.state.focused == true) { styleObj = {outlineStyle: 'none'}; } return styleObj; }
這個方法在focus的時候去除了input默認的效果,blur的時候保持原樣。
隨着React學習的深刻,你會發現React添加樣式的方式和以前的方式大有不一樣。若是你透過上面的例子收入思考的話你會發現,之因此React使用了和以往不一樣的添加樣式方法是有緣由的。HTML、CSS和Javascript這樣的傳統方法在處理網頁的時候是很是有用的,可是在處理React組件組成的複雜的界面的web app的時候卻顯得力不從心。