好久好久之前,就有人用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的时候却显得力不从心。