使用React,如何在不在DOM中的情况下使模态do-animated出现



我有一个模态,它出现在按下按钮时,并在显示时设置动画。

这很好,但前提是当按下按钮时模式代码已经在DOM中。

您可以在此处看到示例:https://codesandbox.io/s/loving-dan-7fwrkr

这就是问题所在:如果按钮将模态代码添加到DOM中,那么模态只会在没有动画的情况下出现

我花了很多时间尝试各种方法来实现这一点,我能想到的最好的方法是在模式代码添加到DOM后200毫秒使用window.setTimeout来触发动画。我不喜欢这样的解决方案,因为它看起来像是一个黑客——我不清楚为什么这样的黑客会起作用。

下面的示例演示了这两种情况。

如果没有注释的代码,动画就可以工作。

使用带注释的代码,模态只是在没有动画的情况下出现。

如果有人知道如何解决这个问题,我们将不胜感激。

我的具体目标是在按下按钮使其出现之前,不要在DOM中包含模态代码。

我已经非常努力地制作了下面的最小可能的例子,但它仍然相当大,我道歉。如果你有进一步削减的建议,同时仍然相关,请告诉我。

import ReactDOM from 'react-dom';
import React, {useState} from 'react';
const theStyle = `
.md-modal {
position: fixed;
top: 50%;
left: 50%;
width: 50%;
height: auto;
z-index: 2000;
visibility: hidden;
transform: translateX(-50%) translateY(-50%);
}

.md-show {
visibility: visible;
}

.md-overlay {
position: fixed;
width: 100%;
height: 100%;
visibility: hidden;
top: 0;
left: 0;
z-index: 1000;
opacity: 0;
background: rgba(143, 27, 15, 0.8);
transition: all 0.3s;
}

.md-show ~ .md-overlay {
opacity: 1;
visibility: visible;
}

.md-content {
color: #fff;
background: #e74c3c;
position: relative;
border-radius: 3px;
margin: 0 auto;
}

.md-content h3 {
opacity: 0.8;
}

.md-effect-1 .md-content {
transform: scale(0.7);
opacity: 0;
transition: all 0.3s;
}

.md-show.md-effect-1 .md-content {
transform: scale(1);
opacity: 1;
}
`
function App() {
const [getVisible, setVisible] = useState(false);
/*
THE MODAL APPEAR ANIMATION DOES NOT WORK WHEN THIS IS UNCOMMENTED
if (!getVisible) {
return (
<button onClick={() => setVisible(true)}>
show modal
</button>)
}
*/
return (
<>
<style>
{theStyle}
</style>
<div className={`md-modal md-effect-1 ${(getVisible) && "md-show"}`}>
<div className="md-content">
This is a modal window.<br/>
<button onClick={() => setVisible(false)} className="md-close">close</button>
</div>
</div>
<div onClick={() => setVisible(false)} className="md-overlay"/>
<button onClick={() => setVisible(true)} className="md-trigger">
show modal
</button>
</>
);
}
ReactDOM.render(<App/>, document.getElementById('root'));

我也遇到过类似的问题,原因是如果将模态添加到DOM时,模态立即获得可见的end value,则transition不会触发。

我通过将转换放入@keyframes动画中解决了这个问题。然后,在将模态添加到DOM之后,使用classList.add()来触发动画。

像这样的

.modal {
opacity:0
}
.animated {
animation: showModal 1s forwards easeOut
}
@keyframes showModal {
from {
opacity: 0;
}
to {
opacity: 1;
}
}

将模态添加到DOM后的JS:

myModel.classList.add("animated")

自我回答我未来的自我。

以@Kokodoko的答案作为我的起点,我更好地理解了动画在CSS/JS中的工作方式,并完全重写了我的模态,这样它现在就可以随心所欲了。

这是代码:

import ReactDOM from 'react-dom';
import React, {useState} from 'react';
const theStyle = `

.animated {
animation: showModal .2s forwards 
}

@keyframes showModal {
from {
opacity: 0;
transform: scale(0.7);
}

to {
opacity: 1;
transform: scale(1);
}
}
.modalOverlay {
z-index: 1500;
background: rgba(40,91,218,0.5); /* you must use this and not opacity because opacity changes the front color */
position: fixed;
width: 100%;
height: 100%;
top: 0;
left: 0;
margin: 0;
padding: 0;
display: flex;
flex-direction: row;
flex-wrap: nowrap;
justify-content: center;
align-content: stretch;
align-items: center;
}

.modalContainer {
z-index: 1600;
order: 0;
flex: 0 1 auto;
align-self: auto;
}
#modalContent {
z-index: 1700;
opacity: 0;
color: #fff;
width: 500px;
height: 200px;
background: #e74c3c;
position: relative;
border-radius: 3px;
margin: 0 auto;
}

`
function Button() {
const [getVisible, setVisible] = useState(false);
return (
<div>
<button onClick={() => setVisible(true)}>
show modal
</button>
{(getVisible) && <Modal setVisible={setVisible}/>}
</div>
)
}
function Modal({setVisible}) {
React.useEffect(
//() => window.setTimeout(document.getElementById("modalContent").classList.add("animated"))
() => document.getElementById("modalContent").classList.add("animated")
, [])
const handleClickOnOverlay = (e) => {
// clicks on the are sent through to the background so we must prevent that
e.stopPropagation()
setVisible(false)
}
const handleClickOnContainer = (e) => {
// clicks on the modal are sent through to the background so we must prevent that
e.stopPropagation()
}
const handleClickOnModal = (e) => {
console.log('clicked on modal')
}
return (
<>
<style>
{theStyle}
</style>
<div onClick={handleClickOnOverlay} className="modalOverlay">
<div className={`modalContainer`} onClick={handleClickOnContainer}>
<div id="modalContent" onClick={handleClickOnModal}>
This is a modal window.<br/>
<button onClick={() => setVisible(false)} className="md-close">close</button>
</div>
</div>
</div>
</>
);
}
ReactDOM.render(<Button/>, document.getElementById('root'));

最新更新