我正在尝试将错误消息显示为 toast (React 组件),该消息将在几秒钟后淡出。然而,当用户在淡出时将鼠标悬停在 toast 上时,淡出应该停止并且 toast 应该恢复到其初始状态,当他将鼠标悬停在 toast 上时,淡出应该再次开始.它可以通过像这样使用 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 并使用react。
我试图通过在 mouseEnter 和 mouseLeave 事件上操纵 CSS 不透明度来实现它。我面临的问题是 toast 永远不会离开使用不透明度的页面。有什么方法可以检测 toast 的不透明度何时变为 0,以便我可以在不透明度变为 0 时将其从页面中删除?
有人可以帮助我在不使用 Jquery 的情况下实现同样的目标吗?
最佳答案
对于淡入淡出的动画,我会使用 React-Spring .使用 Spring
,您可以延迟开始动画,这样它会在延迟后淡出。
然后你可以添加 onMouseEnter
和 onMouseLeave
事件处理程序来检测 toastr 的悬停。
通过此鼠标检测,您可以将 Spring 的 to
值切换为 opacity
1。这样,如果鼠标在 toast 上,它就不会淡出.
要删除 toastr,您可以使用 Spring 的 onRest
并检查 opacity
是否为零。 onRest
将在动画结束时立即调用。
状态管理在 Toastr
组件内完成,它将呈现所有显示的 toasts
。该组件还将处理不透明的 toast 的移除。
对于点击事件 addToast
,我使用了高阶组件 withToastr
,因此我可以将 的属性添加到包含的组件。
对于事件处理,我使用 Eventemitter3 .如果您使用的是 Redux,您还可以使用它来触发 toast 。
在接下来的部分中,我将详细介绍我在以下 Codesandbox 中创建的每个组件. (注意:此处的代码片段未运行 - 要测试代码,请查看沙箱)
ToastrItem
组件
负责渲染 toast 和动画。
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;
Spring 正在执行前面提到的动画。鼠标事件 enter
/leave
正在设置本地状态 hovered
因此我们可以更改动画结束的不透明度 - 这将避免动画。
我还尝试了 React-Spring
的 reset
Prop ,但没有按预期工作。
Toastr
组件
此组件正在管理事件 toast。这里没什么特别的。它正在呈现使用 addToast
添加的 toasts 数组。
addToast
正在创建一个具有时间戳和数组索引的相对唯一的键。它是必需的,因此 React 在组件上获得了关键支持。我们也可以在这里使用 uuid 库,但我认为 timestamp-id 没问题。
如果不透明度为 0,将调用 destroy
然后它会按键过滤并更新状态。 map 就在那里,所以我们正在更新 toast 的位置。
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} />;
}
};
};
在应用中的使用
我们正在使用 withToastr(App)
添加 addToast
。这会将 Prop addToastr 添加到 App 组件。
然后我们渲染 Toastr
组件,它将管理和渲染我们的 toasts。
最后,我们添加一个按钮,以便我们可以触发 toast 。
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);
结论
代码正在运行,但我会向 Spring 添加 native
属性,我还会检查转换是否更适合用例。请参阅 MessageHub example 中的示例来自 React-spring 文档。应该也可以防止淡出,但我没有检查过。
关于javascript - 在没有 Jquery 的情况下,在 mouseEnter 和 mouseLeave 上 react 停止/开始淡出,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53659477/