React—10—过渡动画;React使用CSS的几种方式;React如何给元素动态添加类;
一、react-transition-grou过渡动画
react-transition-group本质是自动给我们添加类和删除类,具体的过渡动画效果还是要我们自己写。
(一)CSSTransition组件
- 第一类,开始状态:对于的类是-appear、-enter、exit;
- 第二类:执行动画:对应的类是-appear-active、-enter-active、-exit-active;
- 第三类:执行结束:对应的类是-appear-done、-enter-done、-exit-done;
appear appear是初次显示动画,和enter的区别是只有第一次显示会走apper,后面的显示都走enter。 enter enter是元素显示的动画,即进入动画,进入有三个状态,初始的enter、执行动画期间的enter-active、执行结束后的enter-done/ 并且react是给元素先加入enter类,在加入enter-active类, 最终经过我们写的timeout时间后,把enter和enter-active都去掉,加入enter-done类。 所以,如果我们想实现一个隐入隐出的效果, 可以在enter类里写opacity:0 然后react会立马在enter类保留的基础上,在添加一个enter-acitve类,这个时候enter-acitve类就写 opacity:1; transition:all 2s ease; 这样,这个元素的opacity属性就从0变到了1,然后由于我们加了一个transition的效果,所以opacity在变化的时候,会有动态效果。 最终在经过timeout时间后,react会把enter和enter-active类都去掉,然后加入enter-done类。 exit exit是元素消失的动画 用法和enter一样。
import React, { PureComponent } from 'react'; import { CSSTransition } from 'react-transition-group'; import './style.css'; // 编写一个组件 class App extends PureComponent { constructor() { super(); this.state = { isShow: true }; } render() { const { isShow } = this.state; return ( <div> <button onClick={e => this.setState({ isShow: !isShow })}>切换</button> <CSSTransition in={isShow} appear classNames="foo" timeout={2000} unmountOnExit={true}> <div> <h1>过渡动画</h1> </div> </CSSTransition> </div> ); } } export default App;
样式:::::::::::::::::::::::::
1.3CSSTransition常见对应的属性:
in:触发进入或者退出状态
-
如果添加了unmountOnExit={true},那么该组件会在执行退出动画结束后被移除掉;
-
当in为true时,触发进入状态,会添加-enter、-enter-acitve的class开始执行动画,当动画执行结束后,会移除两个class,
-
并且添加-enter-done的class;
-
当in为false时,触发退出状态,会添加-exit、-exit-active的class开始执行动画,当动画执行结束后,会移除两个class,并
-
且添加-enter-done的class;
classNames:动画class的名称, 决定了在编写css时,对应的class名称:比如card-enter、card-enter-active、card-enter-done;
timeout:过渡动画的时间
appear:是否在初次进入添加动画(需要和in同时为true)
unmountOnExit:退出后是否卸载组件
1.4 CSSTransition对应的钩子函数:
(二)SwitchTransition
CSSTransition:一个是单独组件的显示和消失。
SwitchTransition:一个两个组件的切换。
key
,以便 TransitionGroup
正确地识别到每个组件,方便key不同时,TransitionGroup
来切换。import React, { useState } from 'react'; import { TransitionGroup, CSSTransition } from 'react-transition-group'; import './styles.css'; // 包含过渡效果的 CSS 样式 // 定义五个简单的组件 const ComponentOne = () => <div className="component">组件一</div>; const ComponentTwo = () => <div className="component">组件二</div>; const ComponentThree = () => <div className="component">组件三</div>; const ComponentFour = () => <div className="component">组件四</div>; const ComponentFive = () => <div className="component">组件五</div>; function App() { const [activeIndex, setActiveIndex] = useState(0); // 组件列表 const components = [ <ComponentOne key="one" />, <ComponentTwo key="two" />, <ComponentThree key="three" />, <ComponentFour key="four" />, <ComponentFive key="five" /> ]; // 切换到下一个组件 const handleNext = () => { setActiveIndex((prevIndex) => (prevIndex + 1) % components.length); }; return ( <div> <button onClick={handleNext}>切换组件</button> <TransitionGroup> <CSSTransition key={activeIndex} // 使用 activeIndex 作为 key timeout={500} classNames="fade" > {components[activeIndex]} </CSSTransition> </TransitionGroup> </div> ); } export default App;
.fade-enter { opacity: 0; } .fade-enter-active { opacity: 1; transition: opacity 500ms; } .fade-exit { opacity: 1; } .fade-exit-active { opacity: 0; transition: opacity 500ms; } .component { padding: 20px; border: 1px solid #ccc; margin-top: 10px; }
(三)TransitionGroup
CSSTransition:单独组件切换(显示和消失)
SwitchTransition:两个组件的切换。
TransitionGroup:一组组件中,增加或删除某个组件。
二、React如何使用CSS
2.1内联样式
2.2普通CSS
2.3CSS modules
2.4 CSS in JS
2.5 css in js的重点框架, styled-components
- 这个组件会被自动添加上一个不重复的class;
- styled-components会给该class添加相关的样式;
- 支持直接子代选择器或后代选择器,并且直接编写样式;
- 可以通过&符号获取当前元素;
- 直接伪类选择器、伪元素等;
2.6 styled-components的props属性和attrs属性
import React, { PureComponent } from 'react'; import { AppWrapper, PartWrapper, DefaultWrapper } from './style'; // 编写一个组件 class App extends PureComponent { constructor() { super(); this.state = { isShow: true, fontSize: '32px', color: 'skyBlue' }; } render() { const { isShow, fontSize, color } = this.state; return ( <div> <button onClick={e => this.setState({ isShow: !isShow })}>切换</button> <AppWrapper> <h1 className="head">头部</h1> <div className="body">body</div> <footer> 脚{/* 给样式组件传递一些变量 */} <PartWrapper fontSize={fontSize} color={color}> <div className="section"> <div>1</div> <div>2</div> <div>3</div> </div> </PartWrapper> <DefaultWrapper color2={color}> <div className="section2">section2</div> <div className="section3">section3</div> </DefaultWrapper> </footer> </AppWrapper> </div> ); } } export default App;
import styled from 'styled-components'; export const AppWrapper = styled.div` .head { color: red; } .body { background-color: #f2f2f2; &:hover { background-color: skyblue; } } footer { color: blue; } `; export const PartWrapper = styled.div` .section { width: 100px; height: 50px; margin: 0 auto; color: ${props => props.color}; font-size: ${props => props.fontSize}; border: 1px solid skyblue; display: flex; flex-direction: row; flex-wrap: nowrap; justify-content: space-around; align-items: center; } `; // attrs属性,可以给组件添加属性,这样除了父组件穿的propos属性,还有自己定义的属性。 // color2属性: 可以先判断父组件里是否有传值,有则取父组件传的值,没有则默认给值。 // color3属性: 直接给默认值 export const DefaultWrapper = styled.div.attrs(props => ({ color2: props.color2 || 'red', color3: '#fff' }))` .section2 { color: ${props => props.color2}; } .section3 { color: ${props => props.color3}; } `;
项目中,全局变量和组件的样式都用style-components来写,style-components也支持less的全局变量定义、变量使用、嵌套语法等,还可以通过props获取动态变量。
现代css也支持变量和嵌套语法了,less给我的感觉是用处不大了,可能只有一个预处理器把css的一些写法转化成老浏览器能识别的作用吧。
注意: 我本来想试着在style-component使用less定义的变量@primary-color,发现无法获取。但是css原生定义的变量
:root{
--primary-color:red
}
style-components是可以获取到的。
原因CSS 变量是浏览器原生支持的特性,styled-components
可以直接访问这些变量,因为它们是在浏览器运行时解析的。
Less 是一种 CSS 预处理器,它的变量在编译时被替换为具体的值,编译后生成的 CSS 文件中不再保留变量信息。styled-components
无法直接访问 Less 变量,因为它们在运行时已经不存在。
所以 style-components想使用变量,要么使用css原生变量配置,要么直接配置一个全局js文件然后在所有需要用到的文件导入即可,如果嫌所有要用到的文件都要导入麻烦那么就使用theme配置即可。
三、React动态给元素添加class
第一步: npm install classNames
第二步:
import React, { PureComponent } from 'react'; import classNames from 'classnames'; // 编写一个组件 class App extends PureComponent { constructor() { super(); this.state = { isFoo: true }; } render() { const { isFoo } = this.state; return ( <div> <h1 className={classNames({ foo: isFoo })}>头部</h1> </div> ); } } export default App;