使用带有样式组件的 ReactCSSTransitionGroup

Posted

技术标签:

【中文标题】使用带有样式组件的 ReactCSSTransitionGroup【英文标题】:Using ReactCSSTransitionGroup with styled-component 【发布时间】:2017-07-28 09:43:54 【问题描述】:

我正在使用 styled-components 而不是传统的 css 方式。但是不知道怎么和ReactCSSTransitionGroup一起工作。

基本上,ReactCSSTransitionGroup 在 css 资源中查找某些类名,然后在组件的整个生命周期中应用到组件。但是,styled-components 没有任何类名,样式直接应用于组件。

我知道我可以选择不使用ReactCSSTransitionGroup,因为这两种技术看起来不兼容。但是当我只使用styled-components 时,卸载组件时似乎无法渲染任何动画 - 它是纯 css,无法访问组件的生命周期。

感谢任何帮助或建议。

【问题讨论】:

【参考方案1】:

我不想像另一个答案中建议的那样使用injectGlobal,因为我需要使每个组件的转换不同。

事实证明这很简单 - 只需将转换类嵌套在组件的样式中即可:

import React from "react";
import CSSTransitionGroup from 'react-transition-group/CSSTransitionGroup';
import styled from 'styled-components';

const appearDuration = 500;
const transitionName = `example`;

const Container = styled.section`
        font-size: 1.5em;
        padding: 0;
        margin: 0;

        &.$transitionName-appear 
            opacity: 0.01;
        

        &.$transitionName-appear-active 
            opacity: 1;
            transition: opacity $appearDurationms ease-out;
        `;

export default () => 

    return (
        <CSSTransitionGroup
            transitionName=transitionName
            transitionAppear=true
            transitionAppearTimeout=appearDuration>
            <Container>
                This will have the appear transition applied!
            </Container>
        </CSSTransitionGroup>
    );
;

请注意,我使用的是较新的 CSSTransitionGroup,而不是 ReactCSSTransitionGroup,但它也应该适用。

【讨论】:

【参考方案2】:

Mike Goatly's approach 很棒,但我必须进行一些小改动才能使其正常工作。我更改了&lt;CSSTransition&gt; 的props,并使用了一个函数作为它的子函数。

请参阅下面的组件示例,该组件根据状态更改淡入/淡出:

import React,  Component  from "react";
import ReactDOM from "react-dom";
import  CSSTransition  from "react-transition-group";
import styled from "styled-components";

const Box = styled.div`
  width: 300px;
  height: 300px;
  background: red;
  transition: opacity 0.3s;

  // enter from
  &.fade-enter 
    opacity: 0;
  

  // enter to
  &.fade-enter-active 
    opacity: 1;
  

  // exit from
  &.fade-exit 
    opacity: 1;
  

  // exit to 
  &.fade-exit-active 
    opacity: 0;
  
`;

export default class App extends Component 
  constructor() 
    super();
    this.state = 
      active: true
    ;

    setInterval(() => this.setState( active: !this.state.active ), 1000);
  

  render() 
    return (
      <CSSTransition
        in=this.state.active
        classNames="fade"
        timeout=300
        unmountOnExit
      >
        () => <Box />
      </CSSTransition>
    );
  

【讨论】:

【参考方案3】:

您可以在样式组件中使用 css 变量选择器。像这样:

const Animation = styled(ReactCSSTransitionGroup)`
  $( transitionName ) => `.$transitionName-enter` 
    opacity: 0;
  

  $(transitionName) => `.$transitionName-leave` 
    opacity: 1;
  
`

const animationID = 'some-hashed-text'

const AnimationComponent = props => (
  <Animation
    transitionName=animationID
    transitionEnterTimeout=0.1
    transitionLeaveTimeout=2000
  >
    <div>some content</div>
  </Animation>
)

【讨论】:

这在与transitionAppear 结合使用时对我有用,但我认为这是错误的方法,因为CSSTransitionGroup 旨在保持静态并处理其中的元素。我无法应用任何休假转换,因为如果有条件地呈现整个 CSSTransitionGroup 将被删除【参考方案4】:

使用 injectGlobal() styled-component 辅助方法来引导您的 React 应用程序。使用这种方法,您可以设置任何 CSS 选择器的样式,就像使用传统 CSS 一样。

首先创建一个 JS 文件,使用您的 CSS 为 react-transition-group 导出模板文字(请不要我使用 v2.1 新类名语法):

globalCss.js

const globalCss = `
    .transition-classes 
        /* The double class name is to add more specifity */
        /* so that this CSS has preference over the component one. */
        /* Try removing it, you may not need it if properties don't collide */
        /* https://www.styled-components.com/docs/advanced#issues-with-specificity */

        &-enter&-enter 
        

        &-enter&-enter-active 
        

        &-exit&-exit 
        

        &-exit&-exit-active 
        
    
`;

export default globalCss;

然后在你的入口点文件上:

index.jsx

import  injectGlobal  from "styled-components";
import globalCss from "./globalCss.js";

injectGlobal`$ globalCss `; // <-- This will do the trick

ReactDOM.render(
    <Provider store= Store  >
        <HashRouter >
            <Route path="/" component= Component1  />
            <Route path="/" component= Component2  />
        </HashRouter>
    </Provider>,
    document.getElementsByClassName("react-app")[0]
);

但是,如果你只是使用 CSS/SASS/Less 来为 react-trasition-group 编写类,即使你使用 styled-components,它也能很好地工作。

【讨论】:

【参考方案5】:

有一篇很棒的博客文章解释了如何做到这一点: https://dev.to/terrierscript/styled-component--react-transition-group--very-simple-transition-jja

他们使用 react-transition-group 提供的低级 Transiton 组件: http://reactcommunity.org/react-transition-group/transition

// This is overly simplified, but styles change depend on state from Transition
const MyStyledComponent = styled.div`
  transform: translateY($( state ) => (state === 'exited' ? "0" : "-100%"));
  transition: transform 2s;
`

const App = () =>
  <Transition in=animate timeout=500>
    (state) => (
      // state change: exited -> entering -> entered -> exiting -> exited
      <MyStyledComponent state=state>Hello</MyStyledComponent>
    )
  </Transition>

【讨论】:

【参考方案6】:
import React from "react";
import  CSSTransition  from 'react-transition-group';

const styles = theme => (
    'fade-enter':
        opacity: 0,
    ,
    'fade-enter-active':
        opacity: 1,
        transition: "opacity 300ms"
    ,
    'fade-exit':
        opacity: 1,
    ,
    'fade-exit-active':
        opacity: 0,
        transition: "opacity 300ms"
    ,
)

class myAnimatedComponent extends React.Component 

  constructor(props)
    super(props);
  

  render()

    let classes = this.props;

    return (
        <CSSTransition
            in=this.props.conditionVariable
            classNames=
               enter: classes['fade-enter'],
               enterActive: classes['fade-enter-active'],
               exit: classes['fade-exit'],
               exitActive: classes['fade-exit-active'],
            
            timeout=300
            unmountOnExit>
                <span>This will have the transition applied to it!</span>
        </CSSTransition>
    );
  
;

export default (styles)(myAnimatedComponent);

我不得不使用classes['fade-enter'] 等,因为我使用了withStyles,React 改变了这个组件中所有类的名称。也正因为如此,当我导出组件时,React 会将我的类插入到该组件的 props 中,这就是为什么我还必须创建一个名为 classes 的变量来捕获这些类。

【讨论】:

【参考方案7】:

在 CSS 中尝试 camelCase,如下所示。

.enter 


.enterActive  

【讨论】:

以上是关于使用带有样式组件的 ReactCSSTransitionGroup的主要内容,如果未能解决你的问题,请参考以下文章

无法使用带有样式组件的关键帧设置嵌套动画的样式

如何使用带有样式组件的逻辑类

使用带有样式组件的 ReactCSSTransitionGroup

如何在反应中使用带有样式组件的 document.getElementById()?

如何在 React 上正确使用带有样式组件画布的 TypeScript 类型

使用带有 typescript 的样式化组件“as”prop