在没有Mouse的情况下在mouseEnter和mouseLeave上停止/开始淡出反应

时间:2018-12-06 20:50:53

标签: javascript css reactjs

我试图将错误消息显示为烤面包(React Component),该消息将在某些秒后消失。但是,当用户在淡入淡出时将鼠标悬停在吐司上时,淡出应该停止并且吐司应恢复到其初始状态;当用户将鼠标悬停在吐司上时,淡出应该再次开始。可以通过使用JQuery这样实现-

//用于在时间-t秒后开始淡出的功能

static  fadeOutToast(id, t) {
        let toast = document.getElementById(id);
        if (toast) {
          setTimeout(() => {
                   FadeAndRemove('#' + id);
          }, t * 1000);
         }
      }

/ ** * t1-淡出动画的时间 * /

 static FadeAndRemove(id,t1) {
        jQuery(id).fadeOut(t1 * 1000, function () {
          jQuery(this).hide();
        });
          handleReAppear(id);
      }


static handleReAppear(id) {
    jQuery(id).on("mouseover", function (e) {
      jQuery(this).stop(true).fadeIn(0);
    });

    jQuery(id).on("mouseleave", function (e) {
     FadeAndRemove(this);
    });
  }

它工作得很好。但是由于项目的限制,我不应该混淆Jquery并做出反应。

我试图通过操纵mouseEnter和mouseLeave事件的CSS不透明度来实现这一点。我面临的问题是,烤面包永远不会使用不透明性脱离页面。有什么方法可以检测烤面包的不透明度何时变为0,以便我可以在不透明度变为0时将其从页面中删除?

有人可以在不使用Jquery的情况下帮助我实现相同目标吗?

2 个答案:

答案 0 :(得分:0)

对于褪色动画,我将使用React-Spring。使用Spring可以延迟开始动画,以便在延迟之后淡出。 然后,您可以添加onMouseEnteronMouseLeave事件处理程序,以检测烤面包机的悬停状态。

通过这种鼠标检测,您可以将Spring的to值切换为opacity1。这样,如果鼠标悬停在烤面包上,它就不会淡出。

要除去烤面包机,可以使用Spring的onRest,然后检查opacity是否为零。动画结束后,将立即调用onRest

状态管理在Toastr组件内完成,它将呈现所有显示的toasts。该组件还将处理去除不透明的吐司面包。

对于点击事件addToast,我使用的是高阶组件withToastr,因此我可以将prop的属性添加到包含的组件中。

对于事件处理,我使用的是Eventemitter3。如果您使用的是Redux,也可以使用它来触发敬酒。

在接下来的部分中,我将详细介绍在以下Codesandbox中创建的每个组件。 (注意:此处的代码段未运行-要测试代码,请查看沙盒)

ToastrItem组件

负责渲染吐司和动画。

import React, { PureComponent } from "react";
import { Spring } from "react-spring";
import styled from "styled-components";
import PropTypes from "prop-types";

class ToastrItem extends PureComponent {
  static propTypes = {
    id: PropTypes.string,
    timeout: PropTypes.number,
    destroy: PropTypes.func
  };
  static defaultProps = {
    timeout: 5000
  };

  state = {
    hovered: false
  };

  handleRest = ({ opacity }) => {
    if (opacity === 0) {
      this.props.destroy(this.props.id);
    }
  };

  handleMouseEnter = () => {
    this.setState({
      hovered: true
    });
  };

  handleMouseLeave = () => {
    this.setState({
      hovered: false
    });
  };

  render() {
    const { message, index, timeout } = this.props;
    const { hovered } = this.state;
    return (
      <Spring
        config={{ duration: 600, delay: timeout }}
        from={{ opacity: 1.0 }}
        to={{ opacity: hovered ? 1.0 : 0 }}
        onRest={this.handleRest}
      >
        {interpolated => (
          <Wrapper>
            <ToastBox
              onMouseEnter={this.handleMouseEnter}
              onMouseLeave={this.handleMouseLeave}
              pos={index}
              opacity={interpolated.opacity}
            >
              {message}
              {/*- debug info: {JSON.stringify(interpolated)}*/}
            </ToastBox>
          </Wrapper>
        )}
      </Spring>
    );
  }
}

const Wrapper = styled.div`
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  pointer-events: none;
  z-index: 100;
`;

const ToastBox = styled.div.attrs(props => ({
  style: {
    transform: `translateY(${props.pos * 80}px)`,
    opacity: props.opacity
  }
}))`
  width: 60%;
  height: 50px;
  line-height: 50px;
  margin: 0 auto;
  color: white;
  padding: 10px;
  background: rgba(0, 0, 0, 0.8);
  text-align: center;
  box-shadow: 3px 3px 5px rgba(0, 0, 0, 0.5);
  border-radius: 10px;
  pointer-events: auto;
`;

export default ToastrItem;

春天正在做前面提到的动画。鼠标事件enter / leave设置了本地状态hovered,因此我们可以更改动画的末端不透明度-这样可以避免动画。 我还尝试了reset的{​​{1}}道具,但是效果不理想。

React-Spring组件

此组件正在管理活动的吐司。这里没什么特别的。它呈现了Toastr添加的toasts数组。 addToast正在创建带有时间戳和数组索引的相对唯一的键。这是必需的,因此React在组件上获得了关键支撑。我们也可以在这里使用uuid库,但我认为timestamp-id可以。 如果不透明度为0,则会调用addToast,然后按键对其进行过滤并更新状态。地图就在那儿,因此我们正在更新吐司的位置。

destroy

在应用中的用法

我们正在使用class Toastr extends PureComponent { state = { toasts: [] }; addToast = (message, config) => { const index = this.state.toasts.length; const id = `toastr-${Date.now()}-${index}`; const ToastComponent = ( <ToastrItem key={id} id={id} index={index} message={message} timeout={config.timeout || 3000} destroy={this.destroy} /> ); this.setState(state => ({ toasts: [...state.toasts, ToastComponent] })); }; destroy = id => { this.setState(state => ({ toasts: [ ...state.toasts .filter(toast => toast.key !== id) .map((toast, index) => ({ // map for updating index ...toast, props: { ...toast.props, index: index } })) ] })); }; componentDidMount() { emitter.on("add/toastr", this.addToast); } render() { const { toasts } = this.state; return toasts; } } export const withToastr = WrappedComponent => { return class extends PureComponent { render() { return <WrappedComponent addToast={actions.add} />; } }; };添加addToast。这会将prop addToastr添加到App组件。 然后,我们将渲染withToastr(App)组件,该组件将管理和渲染我们的敬酒。 最后,我们添加一个按钮,以便触发吐司。

Toastr

结论

代码正在工作,但是我会在Spring上添加class App extends Component { toastr; render() { const { addToast } = this.props; return ( <div className="App"> <Toastr /> <button onClick={() => addToast("Hello", { timeout: 4000 })}> Show toast </button> </div> ); } } const rootElement = document.getElementById("root"); const AppWithToasts = withToastr(App); ReactDOM.render(<AppWithToasts />, rootElement); prop,并且还要检查过渡是否更适合用例。请参阅来自React-spring文档的MessageHub example中的示例。应该也可以防止淡出,但我没有检查。

答案 1 :(得分:0)

您可能想考虑使用Animatable库。它使用了很容易合并的声明性语法。

import * from 'react-native-animatable';

return(
        <Animatable.View animation="fadeOut" duration={2000} delay={1000}>
            <View>
               {/* YOUR CONTENT */}
            </View>
        </Animatable.View>
    );

https://github.com/oblador/react-native-animatable