我有一个模态,它出现在按下按钮时,并在显示时设置动画。
这很好,但前提是当按下按钮时模式代码已经在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'));