react样式

204 阅读5分钟

react样式

各种写法

内联样式

  • 优点

    • 样式之间不会有冲突
    • 可以动态获取当前state中的状态
  • 缺点

    • 写法上都需要使用驼峰标识
    • 某些样式没有提示
    • 大量的样式,代码混乱
    • 某些样式无法编写(比如伪类/伪元素)

外链样式

将CSS代码写到一个单独的CSS文件中,在使用的时候导入进来

  • 优点
    • 编写简单,有代码提示,支持所有CSS语法
  • 缺点
    • 不可以动态获取当前state中的动态
    • 属于全局的CSS,样式之间会相互影响

模块化

文件名.module.css

  • React的脚手架已经内置了css modules的配置

    • .css/.less/.scss 等样式文件都修改成 .module.css/ .module.less/.module.scss等
  • 优点

    • 编写简单,有代码提示,支持所有css语法
    • 解决了全局样式相互污染问题
  • 缺点

    • 不可以动态获取当前state中的状态
// Main.module.css
.main {
    background: #fff;
}
.title {
    color: aqua;
}

import React from "react"
import MainStyle from './Main.module.css'
import ReactTypes from 'prop-types'
function Main(props) {
    console.log('props', props)
    function btnClick() {
        props.mainFn('main data')
    }
    return (
        <div className={'main'}>
            <div>Main</div>
            <p className={MainStyle.title}>Main123</p>
            <button onClick={btnClick}>按钮</button>
        </div>
    )

}
Main.defaultProps = {
    name: 'main props',
    age: 18
}
Main.propTypes = {
    name: ReactTypes.string,
    age: ReactTypes.number
}
export default Main

Classnames

classnames-github

$npm install classnames
import React, { useState } from 'react'
import classNames from 'classnames'
import './Header.css'
function Header(props) {
    const [isStart, changeDiv] = useState(true)

    const btnClass = classNames({
        div: true,
        'div-start': isStart,
        'div-end': !isStart,
    })
    return (
        <>
            <div className={btnClass}></div>
            <button
                onClick={() => changeDiv(false)}
            >
                123
            </button>
        </>
    )
}
export default Header
.div {
  background-color: aquamarine;
  transition: all 3s;
  width: 100px;
  height: 100px;
  opacity: 1;
}
.div-start {
  width: 0;
  height: 0;
  opacity: 0;
}
.div-end {
  width: 100px;
  height: 100px;
  opacity: 1;
}

style-component

拓展知识:模板字符串

const myname = 'lnj';
const age = 18;
/*
const str = `my name is ${name}, my age is ${age}`;
console.log(str); // my name is lnj, my age is 18
 */

function test(...args) {
    console.log(args);
}
// 在JS中除了可以通过()来调用函数以外,
// 其实我们还可以通过模板字符串来调用函数
// test(1, 3, 5); // [ 1, 3, 5 ]
// test`1, 3, 5`; // [ [ '1, 3, 5' ] ]
// 通过模板字符串调用函数规律
// 参数列表中的第一个参数是一个数组, 这个数组中保存了所有不是插入的值
// 参数列表的第二个参数开始, 保存的就是所有插入的值
// 总结结论
// 我们可以拿到模板字符串中所有的内容
// 我们可以拿到模板字符串中所有非插入的内容
// 我们可以拿到模板字符串中所有插入的内容
// 所以我们就可以对模板字符串中所有的内容进行单独的处理
test`1, 3, 5, ${myname}, ${age}`; // [ [ '1, 3, 5, ', ', ', '' ], 'lnj', 18 ]

css in js

style-component

介绍

styled-components

  • 在React中,React认为结构和逻辑是密不可分的,所以在React中结构代码也是通过JS来编写的。正是受到React这种思想的影响,所以就有很多人开发了用JS来编写CSS的库

    • style-component 、 emotion
  • 利用JS来编写CSS,可以让Css具备样式嵌套、函数定义、逻辑复用、动态修改状态等特性

    • 也就是说, 从某种层面上, 提供了比过去Less/Scss更为强大的功能
    • 所以Css-in-JS, 在React中也是一种比较推荐的方式

使用

  • 安装

    • npm install styled-components --save
  • 导入

    • import styled from 'styled-components'
  • 利用styled-components创建组件并设置样式

 styled.div`
     xxx: xxx
 `
import React from 'react';
import styled from 'styled-components';

// 注意点:
// 默认情况下在webstorm中编写styled-components的代码是没有任何的代码提示的
// 如果想有代码提示, 那么必须给webstorm安装一个插件
const StyleDiv = styled.div`
    p{
        font-size: 50px;
        color: red;
    }
    a{
       font-size: 25px;
       color: green;
    }
`;

class Home extends React.Component{
    render() {
        return (
            <StyleDiv>
                <p>我是home段落</p>
                <a href={'www.it666.com'}>我是home超链接</a>
            </StyleDiv>
        )
    }
}
export default Home;
props、attrs
import React from 'react';
import styled from 'styled-components';
/*
1.styled-components特性
- props
- attrs
* */
const StyleDiv = styled.div`
    p{
        font-size: 50px;
        color: ${props => props.color};
    }
    a{
       font-size: 25px;
       color: green;
    }
`;
// 注意点:
// 调用完attrs方法之后, 这个方法返回的还是一个函数
// 所以我们还可以继续通过字符串模板来调用
const StyleInput = styled.input.attrs({
    type:'password'
})``

class Home extends React.Component{
    constructor(props){
        super(props);
        this.state = {
            color: 'red'
        }
    }
    render() {
        return (
            <StyleDiv color={this.state.color}>
                <p>我是home段落</p>
                <a href={'www.it666.com'}>我是home超链接</a>
                <button onClick={()=>{this.btnClick()}}>按钮</button>
                {/*
                <StyleInput type={'password'}></StyleInput>
                */}
                <StyleInput></StyleInput>
            </StyleDiv>
        )
    }
    btnClick(){
        this.setState({
            color: 'green'
        })
    }
}
export default Home;

设置主题
// APP.js
import React from 'react';
import './App.css'
import Home from './Component/Home'
import About from './Component/About'
import {ThemeProvider} from 'styled-components'

/*
1.设置主题
* */
class App extends React.Component{
    render(){
        return (
            <ThemeProvider theme={{size:'50px', color:'blue'}}>
                <Home></Home>
                <About></About>
            </ThemeProvider>
        );
    }
}
export default App;
import React from 'react';
import styled from 'styled-components';

const StyleDiv = styled.div`
    p{
        font-size: ${props=>props.theme.size};
        color: ${props=>props.theme.color};
    }
`;

class Home extends React.Component{
    render() {
        return (
            <StyleDiv>
                <p>我是home段落</p>
            </StyleDiv>
        )
    }
}
export default Home;
继承
import React from 'react';
import './App.css'
import styled from 'styled-components'

/*
1.继承
https://styled-components.com/docs
* */
/*
const StyleDiv1 = styled.div`
  font-size: 100px;
  color: red;
  background: blue;
`;
const StyleDiv2 = styled.div`
  font-size: 100px;
  color: green;
  background: blue;
`;
 */
const BaseDiv = styled.div`
  font-size: 100px;
  background: blue;
`;
const StyleDiv1 = styled(BaseDiv)`
  color: red;
`;
const StyleDiv2 = styled(BaseDiv)`
  color: green;
`;
class App extends React.Component{
    render(){
        return (
            <div>
                <StyleDiv1>我是div1</StyleDiv1>
                <StyleDiv2>我是div2</StyleDiv2>
            </div>
        );
    }
}
export default App;

动画

原生操作

看上面Classnames的示例代码

react-transition-group

react-transition-group

安装

npm install react-transition-group --save

动画组件:

  • Transition容器组件
    • 该组件是一个和平台无关的组件(不一定要结合CSS);
    • 在前端开发中,我们一般是结合CSS来完成过渡,所以比较常用的是CSSTransition;
  • CSSTransition容器组件
    • 在前端开发中,通常使用CSSTransition来完成过渡动画效果
  • SwitchTransition容器组件
    • 两个组件显示和隐藏切换时,使用该组件
  • TransitionGroup容器组件
    • 将多个动画组件包裹在其中,一般用于列表中元素的动画;

状态

  • appear
    • 初始:-appear / -appear-active / -appear-done [生效需要增加属性appear]
  • enter
    • 进入 -enter / -enter-active / -enter-done
  • exit
    • 退出 -exit / -exit-active / -exit-active

CSSTransition属性

  • in

    • 取值是一个布尔值,false:触发退出动画,true:触发进入动画
  • classNames

    • 指定动画类名的前缀
  • timeout

    • 设置动画超时时间
  • unmountOnExit

    • 如果取值为true, 那么表示退出动画执行完毕之后删除对应的元素

生命周期方法

  • onEnter/onEntering/onEntered
  • onExit/onExiting/onExited

SwitchTransition

  • SwitchTransition可以完成组件切换的动画
  • SwitchTransition组件里面要有CSSTransition或者Transition组件不能直接包裹你想要切换的组件
  • SwitchTransition里面的CSSTransition或Transition组件再像以前那样接受in属性来判断元素是何种状态,
    • 取而代之的是key属性

注意点

开发中一定要保证CSSTransition key的唯一性。原因:当为列表增加,key不唯一,增加相同的内容,只会展示一个。

import React, { useState } from 'react'
import { CSSTransition, SwitchTransition } from 'react-transition-group'
import './Header.css'
function Header(props) {
    const [isShow, setIsShow] = useState(true)
    function myEnterFn() {
        console.log('onEnter')
    }
    function myExitFn() {
        console.log('myExitFn')
    }
    return (
        <>
            <CSSTransition
                in={isShow}
                classNames={'box'}
                timeout={3000}
                unmountOnExit={true}
                appear
                onEnter={myEnterFn}
                onEntering={() => { console.log('onEntering') }}
                onEntered={() => { console.log('onEntered') }}
                onExit={myExitFn}
                onExiting={() => { console.log('onExiting') }}
                onExited={() => { console.log('onExited') }}
            >
                <div></div>
            </CSSTransition>
            <button
                onClick={() => setIsShow(true)}
            >
                显示
            </button>
            <button
                onClick={() => setIsShow(false)}
            >
                隐藏
            </button>
            <SwitchTransition mode={'in-out'}>
                <CSSTransition key={isShow} timeout={3000} classNames={'btn'}>
                    <button className={'btn'} onClick={() => setIsShow(!isShow)}>{isShow ? 'show' : 'notShow'}</button>
                </CSSTransition>
            </SwitchTransition>
        </>
    )
}
export default Header
.box-enter {
  /*进入动画执行之前绑定的类名*/
  width: 0;
  height: 0;
  opacity: 0;
  background: skyblue;
}
.box-enter-active {
  /*进入动画执行过程中绑定的类名*/
  width: 100px;
  height: 100px;
  opacity: 1;
  transition: all 3s;
}
.box-enter-done {
  /*进入动画执行完毕之后绑定的类名*/
  width: 100px;
  height: 100px;
  opacity: 1;
  background: red;
}

.box-exit {
  /*退出动画执行之前绑定的类名*/
  width: 100px;
  height: 100px;
  opacity: 1;
  background: red;
}
.box-exit-active {
  /*退出动画执行过程中绑定的类名*/
  width: 0;
  height: 0;
  opacity: 0;
  transition: all 3s;
}
.box-exit-done {
  /*退出动画执行完毕之后绑定的类名*/
  width: 0;
  height: 0;
  opacity: 0;
  background: skyblue;
}

.box {
  width: 100px;
  height: 100px;
  background: skyblue;
}

.box-appear {
  /*初始化动画执行之前绑定的类名*/
  width: 0;
  height: 0;
  opacity: 0;
  background: skyblue;
}
.box-appear-active {
  /*初始化动画执行过程中绑定的类名*/
  width: 100px;
  height: 100px;
  opacity: 1;
  transition: all 3s;
}
.box-appear-done {
  /*初始化动画执行完毕之后绑定的类名*/
  width: 100px;
  height: 100px;
  opacity: 1;
  background: red;
}
.btn-enter {
  /*进入动画执行之前绑定的类名*/
  opacity: 0;
  transform: translateX(-100%);
}
.btn-enter-active {
  /*进入动画执行过程中绑定的类名*/
  opacity: 1;
  transform: translateX(0);
  transition: all 3s;
}
.btn-enter-done {
  /*进入动画执行完毕之后绑定的类名*/
}

.btn-exit {
  /*退出动画执行之前绑定的类名*/
  opacity: 1;
  transform: translateX(0);
}
.btn-exit-active {
  /*退出动画执行过程中绑定的类名*/
  opacity: 0;
  transform: translateX(100%);
  transition: all 3s;
}
.btn-exit-done {
  /*退出动画执行完毕之后绑定的类名*/
}

.btn {
  padding: 10px 20px;
  margin-left: 50%;
}