玩转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的时候却显得力不从心。

欢迎加群互相学习,共同进步。QQ群:iOS: 58099570 | Android: 572064792 | Nodejs:329118122 做人要厚道,转载请注明出处!



















本文转自张昺华-sky博客园博客,原文链接:http://www.cnblogs.com/sunshine-anycall/p/5858445.html ,如需转载请自行联系原作者
相关文章
|
前端开发 算法 JavaScript
React-组件-内联样式 和 React-组件-列表渲染优化
React-组件-内联样式 和 React-组件-列表渲染优化
121 0
|
前端开发 JavaScript
react 修改 antdesign 的 组件默认样式
react 修改 antdesign 的 组件默认样式
400 0
|
3月前
|
编解码 前端开发 开发者
React 图片组件样式自定义:常见问题与解决方案
在 React 开发中,图片组件的样式自定义常因细节问题导致布局错乱、性能损耗或交互异常。本文系统梳理常见问题及解决方案,涵盖基础样式应用、响应式设计、加载状态与性能优化等,结合代码案例帮助开发者高效实现图片组件的样式控制。重点解决图片尺寸不匹配、边框阴影不一致、移动端显示模糊、加载失败处理及懒加载等问题,并总结易错点和最佳实践,助力开发者提升开发效率和用户体验。
120 22
|
3月前
|
Web App开发 移动开发 前端开发
React 视频播放器样式自定义实战指南
本文详细介绍了如何在React项目中实现视频播放器的样式自定义,涵盖HTML5 `&lt;video&gt;`标签的基础知识、CSS样式定制技巧及常见问题解决方案。针对全屏模式样式失效、移动端触摸事件冲突和进度条样式定制等问题提供了具体代码示例。同时,探讨了视频预加载策略和内存优化方法,并推荐了几款调试工具,帮助开发者提升用户体验和应用性能。
105 6
|
3月前
|
Web App开发 移动开发 前端开发
React音频播放器样式自定义全解析:从入门到避坑指南
在React中使用HTML5原生&lt;audio&gt;标签时,开发者常面临视觉一致性缺失、样式定制局限和交互体验割裂等问题。通过隐藏原生控件并构建自定义UI层,可以实现完全可控的播放器视觉风格,避免状态不同步等典型问题。结合事件监听、进度条拖拽、浏览器兼容性处理及性能优化技巧,可构建高性能、可维护的音频组件,满足跨平台需求。建议优先使用成熟音频库(如react-player),仅在深度定制需求时采用原生方案。
122 12
|
8月前
|
设计模式 缓存 前端开发
React中样式解决方案有哪些?
本文首发于微信公众号“前端徐徐”,探讨了React开发中的样式管理方法,包括内联样式、常规CSS、CSS-Module、CSS-in-JS及使用CSS框架等五种常见方案,分析了各自的优缺点,帮助开发者根据项目需求选择合适的样式解决方案。
191 0
|
10月前
|
前端开发 Java UED
JSF 面向组件开发究竟藏着何种奥秘?带你探寻可复用 UI 组件设计的神秘之路
【8月更文挑战第31天】在现代软件开发中,高效与可维护性至关重要。JavaServer Faces(JSF)框架通过其面向组件的开发模式,提供了构建复杂用户界面的强大工具,特别适用于设计可复用的 UI 组件。通过合理设计组件的功能与外观,可以显著提高开发效率并降低维护成本。本文以一个具体的 `MessageComponent` 示例展示了如何创建可复用的 JSF 组件,并介绍了如何在 JSF 页面中使用这些组件。结合其他技术如 PrimeFaces 和 Bootstrap,可以进一步丰富组件库,提升用户体验。
109 0
|
10月前
|
前端开发 JavaScript 开发者
【前端革新力】React与CSS-in-JS完美邂逅:从styled-components到emotion,全面解析样式管理新趋势的实战应用与优势剖析!
【8月更文挑战第31天】CSS-in-JS 作为一种新兴的样式管理方式,近年来在前端社区受到广泛关注。它将样式嵌入 JavaScript,实现了样式与逻辑的高度耦合,提升了开发效率并解决了全局样式污染等问题。本文通过具体代码示例,探讨 CSS-in-JS 在 React 开发中的应用,并分享实践心得。首先介绍了 CSS-in-JS 的基本概念,然后详细展示了如何使用 styled-components 和 emotion 这两个流行库创建样式化组件。
506 0
|
12月前
|
JSON 弹性计算 前端开发
函数计算产品使用问题之遇到在自定义运行时部署React项目时遇到样式无法正常加载。一般是什么导致的
函数计算产品作为一种事件驱动的全托管计算服务,让用户能够专注于业务逻辑的编写,而无需关心底层服务器的管理与运维。你可以有效地利用函数计算产品来支撑各类应用场景,从简单的数据处理到复杂的业务逻辑,实现快速、高效、低成本的云上部署与运维。以下是一些关于使用函数计算产品的合集和要点,帮助你更好地理解和应用这一服务。
|
前端开发 JavaScript 安全
【亮剑】探讨了在React TypeScript应用中如何通过道具(props)传递CSS样式,以实现模块化、主题化和动态样式
【4月更文挑战第30天】本文探讨了在React TypeScript应用中如何通过道具(props)传递CSS样式,以实现模块化、主题化和动态样式。文章分为三部分:首先解释了样式传递的必要性,包括模块化、主题化和动态样式以及TypeScript集成。接着介绍了内联样式的基本用法和最佳实践,展示了一个使用内联样式自定义按钮颜色的例子。最后,讨论了使用CSS模块和TypeScript接口处理复杂样式的方案,强调了它们在组织和重用样式方面的优势。结合TypeScript,确保了样式的正确性和可维护性,为开发者提供了灵活的样式管理策略。
127 0