如何使过渡项目进入和项目离开没有任何外部库在ReactJS?




我想在不使用任何外部库的情况下,在用户单击按钮时为toast动画。每当用户单击按钮时,我都将toast enter动画化。我尝试用动画来使吐司离开,但是在点击X按钮时,吐司并没有从UI中移除。

Toast.js

import React from "react";
import { connect } from "react-redux";
import { deleteToast } from "./redux/action/actionCreators";
import "./toast.scss";
const Toast = (props) => {
const { toasts, deleteToast } = props;
return (
<div className="toast-container">
{toasts.map((toast, index) => {
return (
<div className={`toast bg-${toast.type} toast-enter`} key={index}>
<div className="toast-header">
<p>{toast.title}</p>
<button onClick={() => deleteToast(toast.id)}>X</button>
</div>
{toast.description && (
<div className="toast-description">
<p>{toast.description}</p>
</div>
)}
</div>
);
})}
</div>
);
};
const mapStateToProps = (state) => ({
toasts: state.toastReducer.toasts,
});
const mapDispatchToProps = (dispatch) => ({
deleteToast: (toastId) => dispatch(deleteToast(toastId)),
});
export default connect(mapStateToProps, mapDispatchToProps)(Toast);

Toast.scss

$bg-danger: #dc3545;
$bg-warning: #ffc107;
$bg-info: #0d6efd;
$bg-success: #198754;
.toast-container {
position: absolute;
right: 1rem;
bottom: 1rem;
z-index: 999;
.toast {
padding: 0.5rem 1rem;
opacity: 0.9;
color: #fff;
width: 250px;
margin-top: 0.5rem;
&:hover {
opacity: 1;
}
}
.toast-enter {
animation: toast-enter-animation 0.3s linear 1;
}
.toast-leave {
animation: toast-leave-animation 0.3s linear 1;
}
.toast-header {
display: flex;
justify-content: space-between;
align-items: center;
}
.toast-header button {
background-color: inherit;
outline: none;
border: none;
color: inherit;
&:hover {
cursor: pointer;
}
}
.bg-danger {
background-color: $bg-danger;
}
.bg-warning {
background-color: $bg-warning;
}
.bg-info {
background-color: $bg-info;
}
.bg-success {
background-color: $bg-success;
}
}
@mixin keyframes($name) {
@-webkit-keyframes #{$name} {
@content;
}
@-moz-keyframes #{$name} {
@content;
}
@-ms-keyframes #{$name} {
@content;
}
@keyframes #{$name} {
@content;
}
}
@include keyframes(toast-enter-animation) {
0% {
transform: translateX(100%);
}
100% {
transform: translateX(0);
}
}
@include keyframes(toast-leave-animation) {
0% {
transform: translateX(0);
}
100% {
transform: translateX(100%);
}
}

App.js

import React from "react";
import { connect } from "react-redux";
import { addToast } from "./Commons/Toast/redux/action/actionCreators";
const App = (props) => {
const { addToast } = props;
return (
<button
onClick={() =>
addToast({
title: "Toast title",
type: "success",
description: "Toast description",
})
}
>
Click
</button>
);
};
const mapStateToProps = (state) => ({});
const mapDispatchToProps = (dispatch) => ({
addToast: (toast) => dispatch(addToast(toast)),
});
export default connect(mapStateToProps, mapDispatchToProps)(App);

我也可以为条目的进入和离开做过渡

Toast.js

const Toasts = (props) => {
const { toasts } = props;
return (
<div className="toast-container">
{toasts.map((toast, index) => (
<ToastItem toast={toast} key={index} />
))}
</div>
);
};

Toast.scss

$margin-right: 1rem;
$margin-bottom: 1rem;
.toast-container {
position: absolute;
right: $margin-right;
bottom: $margin-bottom;
z-index: 999;
}

ToastItem.js

const performAsyncTaskAfter = 300;
const ToastItem = (props) => {
const [shouldDelete, setShouldDelete] = useState(true);
const { toast, deleteToast } = props;
const removeToast = () => {
setShouldDelete(true);
setTimeout(() => {
deleteToast(toast.id);
}, performAsyncTaskAfter);
};
useEffect(() => {
setTimeout(() => {
setShouldDelete(false);
}, performAsyncTaskAfter);
}, []);
return (
<div
className={`toast bg-${toast.type} ${!shouldDelete ? `toast-enter` : ""}`}
>
<div className="toast-header">
<p>{toast.title}</p>
<button onClick={removeToast}>X</button>
</div>
{toast.description && (
<div className="toast-description">
<p>{toast.description}</p>
</div>
)}
</div>
);
};

ToastItem.scss

$bg-danger: #dc3545;
$bg-warning: #ffc107;
$bg-info: #0d6efd;
$bg-success: #198754;
.toast {
padding: 0.5rem 1rem;
opacity: 0.9;
color: #fff;
width: 250px;
margin-top: 0.5rem;
transform: translateX(calc(100% + 1rem));
transition: all 0.3s;
&:hover {
opacity: 1;
}
}
.toast-enter {
transform: translateX(0);
}
.toast-header {
display: flex;
justify-content: space-between;
align-items: center;
}
.toast-header button {
background-color: inherit;
outline: none;
border: none;
color: inherit;
&:hover {
cursor: pointer;
}
}
.bg-danger {
background-color: $bg-danger;
}
.bg-warning {
background-color: $bg-warning;
}
.bg-info {
background-color: $bg-info;
}
.bg-success {
background-color: $bg-success;
}

最新更新