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
$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
介绍
-
在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
安装
npm install react-transition-group --save
动画组件:
- Transition容器组件
- 该组件是一个和平台无关的组件(不一定要结合CSS);
- 在前端开发中,我们一般是结合CSS来完成过渡,所以比较常用的是CSSTransition;
- CSSTransition容器组件
- 在前端开发中,通常使用CSSTransition来完成过渡动画效果
- SwitchTransition容器组件
- 两个组件显示和隐藏切换时,使用该组件
- TransitionGroup容器组件
- 将多个动画组件包裹在其中,一般用于列表中元素的动画;
状态
- appear
- 初始:-appear / -appear-active / -appear-done
[生效需要增加属性appear]
- 初始:-appear / -appear-active / -appear-done
- 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%;
}