玩转React样式
很久很久以前,就有人用CSS来时给HTML内容添加样式。CSS可以最大限度的分离样式和内容,选择器也可以很方便的给某些元素添加样式。你根本找不到任何不用CSS的理由。
但是在React这里就是另外一回事了,虽然React不是不用CSS。但是,它在给元素添加样式的时候方式不同。React的核心哲学之一就是让可视化的组件自包含,并且可复用。这就是为什么HTML元素和Javascript放在一起组成了Component
(组件)。
React的自包含组件需要在定义的时候就定义好样式,这样才能实现自包含。本文即将带你学习如何给React的组件添加样式,当然其中包括如何使用CSS。两个都会讲到,虽然React不鼓励这样。
准备工作
要在HTML也中使用React有两种方法,一个是使用Webpack编译打包,另一个是使用网页直接添加React相关js文件。
用webpack来编译、打包React组件。并在一个index.html的页面中使用该代码。具体的准备步骤可以看这里。最后打包到一个叫做bundle.js的文件中。HTML页面看起来是这样的:
<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代码。
<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是用来请求服务器的,暂时用不到。
无论使用哪一种方式。最后在页面中使用的js都是bundle.js。如果用了webpack的方式,那么bundle.js就是由webpack便已打包生成的。如果用的第二种方法,那么bundle.js就是我们自己手动编写的js代码。
<div id="content" />
React生成的HTML元素都会放在这个div
里面。
项目结构
使用Webpack的话,项目的整体结果是这样的:
-webapp
|--public // webpack 编译打包后的js文件所在目录
|--css // css文件所在的目录
|--src // 使用React编写的代码所在目录
|--index.html // HTML页面
如果你使用网页内部加载React的话,那么就直接在public目录下创建一个bundle.js文件,并在index.html引用即可。
我们就以一个用户登录的界面喂例子。登录,用户需呀输入用户名、密码,然后点击登录按钮。
React代码
我们来看看要实现这个功能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>
在添加样式之后,效果是这样的:
使用CSS添加样式
在React组件上使用CSS样式比你想的还要简单。因为最终React还是把组件都转化成了HTML元素,而你会的各种CSS技巧一样都可以作用在这些元素上。但是还是有一些小小的地方需要注意:
理解生成的HTML
在使用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。
React中使用CSS
首先添加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的方式来添加样式
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的时候却显得力不从心。
玩转React样式的更多相关文章
- react className 有多个值时的处理 / react 样式使用 百分比(%) 报错
1.react className 有多个值时的处理 <fieldset className={`${styles.formFieldset} ${styles.formItem}`}> ...
- 玩转 React(五)- 组件的内部状态和生命周期
文章标题总算是可以正常一点了-- 通过之前的文章我们已经知道:在 React 体系中所谓的 "在 JavaScript 中编写 HTML 代码" 指的是 React 扩展了 Jav ...
- 【react 样式】给react组件指定style
1.使用行内样式(优先级高) 自定义的react组件是没有style属性的,如果要给想给自定义react组件指定style,我的方法是用一个<div>包裹自定义组件,然后给div指定sty ...
- react 样式的写法之一 ---》styled-components的基本使用
[react]---styled-components的基本使用---[WangQi] 一.官网地址 https://www.styled-components.com/ 二.styled-com ...
- react 样式冲突解决方案 styled-components
前置 在 react 中解决组件样式冲突的方案中,如果您喜欢将 css 与 js 分离,可能更习惯于 CSS-Modules:如果习惯了 Vue.js 那样的单文件组件,可能习惯于使用 styled- ...
- 翻译 | 玩转 React 表单 —— 受控组件详解
原文地址:React.js Forms: Controlled Components 原文作者:Loren Stewart 译者:小 B0Y 校对者:珂珂君 本文涵盖以下受控组件: 文本输入框 数字输 ...
- 玩转 React 【第03期】:邂逅 React 组件
上期回顾 前文我们讲解了 React 模板 JSX,接着我们继续来看看 React 组件又是如何工作的呢? 组件化开发到了今天已经是大家的共识,在 React 中,组件同样也是组成我们整个项目的基本单 ...
- 玩转 React【第02期】:恋上 React 模板 JSX
往期回顾 前文中我们讲解了利用 ReactElement 来编写React程序,但是我们也看到这种方式编写 React 特别的麻烦,而且层级结构特别不清晰.今天我们来看一种优雅的编写React的代码的 ...
- 玩转 React 服务器端渲染
React 提供了两个方法 renderToString 和 renderToStaticMarkup 用来将组件(Virtual DOM)输出成 HTML 字符串,这是 React 服务器端渲染的基 ...
随机推荐
- "A transport-level error has occurred when sending the request to the server"的解决办法
http://blog.csdn.net/luckeryin/article/details/4337457 最近在做项目时,遇到一个随机发生的异常:"A transport-level e ...
- 使用maven创建web项目
eclipse 4.5.2中集成了maven,所以我们不用再去安装插件啦. 点击file->new->other->maven->maven project 选择了worksp ...
- Windows资源管理器 已停止工作
解决方案:http://jingyan.baidu.com/article/5225f26b6aa830e6fa0908a8.html
- angular run()运行块
和配置块不同,运行块在注入器创建之后被执行,它是所有AngularJS应用中第一个被执行的方法. 运行块是AngularJS中与main方法最接近的概念.运行块中的代码块通常很难进行单元测试,它是和应 ...
- Oracle命令:授权-收回权限-角色
Oracle命令:授权-收回权限-角色 oracle grant 不论授予何种权限,每条授权(grant)语句总是由三部分组成: 1) 接受者部分是准备获得权限的一个或多个用户的列表. 2)关键字权限 ...
- 关于php Hash算法的一些整理总结
最近在公司内部的分享交流会上,有幸听到了鸟哥的关于php底层的一些算法的分享,虽然当时有些问题没有特别的明白,但是会后,查阅了各种各样的相关资料,对php的一些核心的hash算法有了进一步的理解和认识 ...
- xtrabackup备份与恢复实践
说明 xtrabackup --percona 特点: 开源,在线备份innodb表 支持限速备份,避免对业务造成影响 支持流备 支持增量备份 支持备份文件压缩与加密 支持并行备份与恢复,速度快 ...
- <COM原理和应用>第七章的ITextObject代码是什么?
第7章中有如下的描述:-----------------------------------为了在程序中使用"Text.Object"文本对象,我们利用ClassWizard引 ...
- tomcat7.0 处理问题
修改tomcat的用户密码 打开tomcat的conf/tomcat-users.xml 将<user username="admin" password="123 ...
- 循序渐进之Spring AOP(5) - 创建切面
在掌握了可用的增强后,接下来要做的就是精确的描述切点.前面的示例都是指定一个目标类并把增强织入到所有方法中,实际开发显然会有更精细的筛选需求,比如对所有类中名称以test结尾的方法加入监控执行时间,或 ...