将 style.transform 设置为父组件后模态(子组件)的行为发生奇怪变化
Strange change in the behavior of a modal (child component) after setting style.transform to the parent component
我遇到了模态框外观或行为的奇怪变化。模态框用于放大聊天中发送的图像。聊天上传预览 div 是父元素,而模态是子元素。在我使用某些功能使聊天上传预览可拖动后,这种奇怪的行为开始发生。在正常情况下,模态框会扩展并覆盖整个屏幕,超出上传预览(父组件)的边界。但是,当通过向其添加 transform/translate CSS 属性 使聊天上传预览可拖动时,模式只会扩展并覆盖上传预览器(父元素)的高度和宽度。有趣的是,如果我删除这个可拖动功能 (transform/translate),模态将恢复正常行为,一直扩展到屏幕边缘。我想知道为什么在父组件的样式中添加 transform/translate CSS 属性 会影响子组件的行为。这让我很困惑。请帮忙。
如果没有 transform/translate 添加到父组件(聊天上传预览 div),它通常看起来是这样的:
下面是将 transform/translate 属性 添加到父组件(聊天上传预览 div)后开始查找的方式:
这是聊天上传预览(父级)的 JSX 代码。模态存在于 FilePreview 组件中,其代码也在下方。
{/* CHAT-UPLOAD-PREVIEW */}
{
this.state.chatFiles.length > 0 ?
<div className="chat-upload-preview-1"
ref={this.myUploader}
onMouseMove={this.onMouseMove}
onMouseDown = {() => {this.setState({pressed: true})}}
onMouseUp = {() => {this.setState({pressed: false})}}
>
<p className="close-button-1" onClick={this.closeUploadPreview}>✖</p>
<h3 className="chat-upload-preview-title-1">Preview</h3>
<div className="file-preview-div-1">**<FilePreview files={this.state.chatFiles}
deletePreviewfile={this.deletePreviewfile2}
getReadableFileSizeString={this.getReadableFileSizeString}
/> </div>**
<div className='chat-upload-container-1'>
<img src='/images/chat-upload.jpg' alt="upload" height="70"
width="70" className='chat-upload-3' onClick={this.inputClick2}>
</img>
<input className="file-input" type="file" name="file" id="file-1"
onChange={this.handleChange2} multiple
accept=".jpg, .jpeg, .png, .pdf, .doc, .docx"></input>
<button className="chat-upload-send-button-1" onClick={this.sendImageToChat}>Send</button>
</div>
</div>
:
null
}
这是 FilePreview 组件的代码,它也包含模态代码(在底部)。
import React from 'react'
import './FilePreview.css'
function FilePreview(props) {
return (
<div className="image-preview-container">
<ul className="image-preview-list">
{props.files.map((item) =>
<li className="image-preview-listItem" key={item.name}>
{item.type === "application/pdf" ?
// PDF
<div className="pdf-file" >
<iframe src={URL.createObjectURL(item)} className="iframe-pdf"
height="110" width="100" title="pdf-review">
</iframe>
<a className="pdf-link" href={URL.createObjectURL(item)} target="_blank">view pdf</a>
<button className="document-image-deleter" onClick={() => props.deletePreviewfile(item)}>x</button>
<p className="file-name">{item.name}</p>
<p className="file-size">{props.getReadableFileSizeString(item.size)}</p>
</div>
:
// WORD
item.type === "application/msword" ?
<div className="pdf-file" >
<img className="document-image" src="images\msword.png" alt="your file" height="50" width="50"/>
<a className="pdf-link" href={URL.createObjectURL(item)} target="_blank">download to view</a>
<button className="document-image-deleter" onClick={() => props.deletePreviewfile(item)}>x</button>
<p className="file-name">{item.name}</p>
<p className="file-size">{props.getReadableFileSizeString(item.size)}</p>
</div>
:
// WORD docx
item.type === 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' ?
<div className="pdf-file" >
<img className="document-image" src="images\msword.png" alt="your file" height="50" width="50"/>
<a className="pdf-link" href={URL.createObjectURL(item)} target="_blank">download to view</a>
<button className="document-image-deleter" onClick={() => props.deletePreviewfile(item)}>x</button>
<p className="file-name">{item.name}</p>
<p className="file-size">{props.getReadableFileSizeString(item.size)}</p>
</div>
:
// Image - Jpeg
item.type === "image/jpeg" ?
<div className="image-file">
{console.log(URL.createObjectURL(item))}
<img className="document-image" src={URL.createObjectURL(item)} alt="your file" height="50" width="50"
onClick={() => {
const modal = document.getElementById("myModal");
const modalImg = document.getElementById("img01");
modal.style.display = "block";
modalImg.src = URL.createObjectURL(item);
}}>
</img>
<button className="document-image-deleter" onClick={() => props.deletePreviewfile(item)}>x</button>
<p className="file-name">{item.name}</p>
<p className="file-size">{props.getReadableFileSizeString(item.size)}</p>
</div>
:
// Image - png
item.type === "image/png" ?
<div className="image-file">
{console.log(URL.createObjectURL(item))}
<img className="document-image" src={URL.createObjectURL(item)} alt="your file" height="50" width="50"
onClick={() => {
const modal = document.getElementById("myModal");
const modalImg = document.getElementById("img01");
modal.style.display = "block";
modalImg.src = URL.createObjectURL(item);
}}>
</img>
<button className="document-image-deleter" onClick={() => props.deletePreviewfile(item)}>x</button>
<p className="file-name">{item.name}</p>
<p className="file-size">{props.getReadableFileSizeString(item.size)}</p>
</div>
:
// Others to be added
<div className="image-file">
<img className="document-image" src={URL.createObjectURL(item)} alt="your file" height="50" width="50"
onClick={() => {
const modal = document.getElementById("myModal");
const modalImg = document.getElementById("img01");
modal.style.display = "block";
modalImg.src = URL.createObjectURL(item);
}}>
</img>
<button className="document-image-deleter" onClick={() => props.deletePreviewfile(item)}>x</button>
<p className="file-name">{item.name}</p>
<p className="file-size">{props.getReadableFileSizeString(item.size)}</p>
</div>
}
{/* The Image PopUp */}
<div id="myModal" className="modal">
{/* the close button (x) */}
<span className="close" onClick={() => {
const modal = document.getElementById("myModal");
modal.style.display = "none";
}}>×</span>
{/* the image itself */}
<img className="modal-content" id="img01" alt="Something"></img>
{/* Text needs to be added */}
<div id="caption"></div>
</div>
</li>
)}
</ul>
</div>
)
}
export default FilePreview
这里又是模态的 JSX:
{/* The Image PopUp */}
<div id="myModal" className="modal">
{/* the close button (x) */}
<span className="close" onClick={() => {
const modal = document.getElementById("myModal");
modal.style.display = "none";
}}>×</span>
{/* the image itself */}
<img className="modal-content" id="img01" alt="Something"></img>
{/* Text needs to be added */}
<div id="caption"></div>
</div>
这里是添加transform/translate 属性拖拽聊天上传预览的功能。它似乎是模态奇怪行为的罪魁祸首,因为当我删除它时,模态再次表现良好。
componentDidUpdate () {
if (this.myUploader.current) {
this.myUploader.current.style.transform = `translate(${this.state.position.x}px, ${this.state.position.y}px)`
document.onmouseup = () => {this.setState({pressed: false})}
}
}
这是聊天上传预览的(父组件)CSS:
.chat-upload-preview-1 {
position: absolute;
bottom: 30px;
left: 300px;
background-color: blanchedalmond;
width: 330px;
height: 600px;
border-radius: 20px;
opacity: 0.9;
}
这是模态的 css:
/* The Modal (background) */
.modal {
display: none; /* Hidden by default */
position: fixed; /* Stay in place */
z-index: 1; /* Sit on top */
padding-top: 100px; /* Location of the box */
left: 0;
top: 0;
width: 100%; /* Full width */
height: 100%; /* Full height */
overflow: auto; /* Enable scroll if needed */
background-color: rgb(0, 0, 0); /* Fallback color */
background-color: rgba(0, 0, 0, 0.9); /* Black w/ opacity */
}
/* Modal Content (image) */
.modal-content {
margin: auto;
display: block;
width: 80%;
max-width: 700px;
}
/* Caption of Modal Image */
#caption {
margin: auto;
display: block;
width: 80%;
max-width: 700px;
text-align: center;
color: #ccc;
padding: 10px 0;
height: 150px;
}
/* Add Animation */
.modal-content,
#caption {
-webkit-animation-name: zoom;
-webkit-animation-duration: 0.6s;
animation-name: zoom;
animation-duration: 0.6s;
}
@-webkit-keyframes zoom {
from {
-webkit-transform: scale(0);
}
to {
-webkit-transform: scale(1);
}
}
@keyframes zoom {
from {
transform: scale(0);
}
to {
transform: scale(1);
}
}
我只是不知道一旦上传预览添加了 transform/translate 属性 模态框会发生什么。为什么它不会像添加 transform/translate 属性 之前那样充分扩展?我完全不解。
所以,我自己找到了答案。答案在关于转换的 MDN 文章中:https://developer.mozilla.org/en-US/docs/Web/CSS/transform
答案:如果变换 属性 的值不同于 none,将创建一个堆叠上下文。在这种情况下,该元素(具有变换 属性 的元素)将充当任何位置的包含块:固定;或位置:绝对;它包含的元素(模态div)。
问题确实出在转换 CSS 函数中。事实证明,Transform 将可拖动元素更改为一个包含块,该块将其内部的所有元素限制在其尺寸限制内。换句话说,所有内部元素都不会大于它的高度或宽度。
更具体地说,Modal div 没有展开以填满整个屏幕,因为变换 属性 是在拖动时添加到 FilePreview 组件的。结果,image-preview-container div(父元素)成为模态 div(子元素)的包含块,将其限制在其 limits/margins.[=11= 内]
因此,解决方法是在单击图像时从包含块中删除变换 属性,以便它可以像以前一样填满整个屏幕:
if (props.myUploader) { props.myUploader.current.style.transform = 'none'
}
我遇到了模态框外观或行为的奇怪变化。模态框用于放大聊天中发送的图像。聊天上传预览 div 是父元素,而模态是子元素。在我使用某些功能使聊天上传预览可拖动后,这种奇怪的行为开始发生。在正常情况下,模态框会扩展并覆盖整个屏幕,超出上传预览(父组件)的边界。但是,当通过向其添加 transform/translate CSS 属性 使聊天上传预览可拖动时,模式只会扩展并覆盖上传预览器(父元素)的高度和宽度。有趣的是,如果我删除这个可拖动功能 (transform/translate),模态将恢复正常行为,一直扩展到屏幕边缘。我想知道为什么在父组件的样式中添加 transform/translate CSS 属性 会影响子组件的行为。这让我很困惑。请帮忙。
如果没有 transform/translate 添加到父组件(聊天上传预览 div),它通常看起来是这样的:
下面是将 transform/translate 属性 添加到父组件(聊天上传预览 div)后开始查找的方式:
这是聊天上传预览(父级)的 JSX 代码。模态存在于 FilePreview 组件中,其代码也在下方。
{/* CHAT-UPLOAD-PREVIEW */}
{
this.state.chatFiles.length > 0 ?
<div className="chat-upload-preview-1"
ref={this.myUploader}
onMouseMove={this.onMouseMove}
onMouseDown = {() => {this.setState({pressed: true})}}
onMouseUp = {() => {this.setState({pressed: false})}}
>
<p className="close-button-1" onClick={this.closeUploadPreview}>✖</p>
<h3 className="chat-upload-preview-title-1">Preview</h3>
<div className="file-preview-div-1">**<FilePreview files={this.state.chatFiles}
deletePreviewfile={this.deletePreviewfile2}
getReadableFileSizeString={this.getReadableFileSizeString}
/> </div>**
<div className='chat-upload-container-1'>
<img src='/images/chat-upload.jpg' alt="upload" height="70"
width="70" className='chat-upload-3' onClick={this.inputClick2}>
</img>
<input className="file-input" type="file" name="file" id="file-1"
onChange={this.handleChange2} multiple
accept=".jpg, .jpeg, .png, .pdf, .doc, .docx"></input>
<button className="chat-upload-send-button-1" onClick={this.sendImageToChat}>Send</button>
</div>
</div>
:
null
}
这是 FilePreview 组件的代码,它也包含模态代码(在底部)。
import React from 'react'
import './FilePreview.css'
function FilePreview(props) {
return (
<div className="image-preview-container">
<ul className="image-preview-list">
{props.files.map((item) =>
<li className="image-preview-listItem" key={item.name}>
{item.type === "application/pdf" ?
// PDF
<div className="pdf-file" >
<iframe src={URL.createObjectURL(item)} className="iframe-pdf"
height="110" width="100" title="pdf-review">
</iframe>
<a className="pdf-link" href={URL.createObjectURL(item)} target="_blank">view pdf</a>
<button className="document-image-deleter" onClick={() => props.deletePreviewfile(item)}>x</button>
<p className="file-name">{item.name}</p>
<p className="file-size">{props.getReadableFileSizeString(item.size)}</p>
</div>
:
// WORD
item.type === "application/msword" ?
<div className="pdf-file" >
<img className="document-image" src="images\msword.png" alt="your file" height="50" width="50"/>
<a className="pdf-link" href={URL.createObjectURL(item)} target="_blank">download to view</a>
<button className="document-image-deleter" onClick={() => props.deletePreviewfile(item)}>x</button>
<p className="file-name">{item.name}</p>
<p className="file-size">{props.getReadableFileSizeString(item.size)}</p>
</div>
:
// WORD docx
item.type === 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' ?
<div className="pdf-file" >
<img className="document-image" src="images\msword.png" alt="your file" height="50" width="50"/>
<a className="pdf-link" href={URL.createObjectURL(item)} target="_blank">download to view</a>
<button className="document-image-deleter" onClick={() => props.deletePreviewfile(item)}>x</button>
<p className="file-name">{item.name}</p>
<p className="file-size">{props.getReadableFileSizeString(item.size)}</p>
</div>
:
// Image - Jpeg
item.type === "image/jpeg" ?
<div className="image-file">
{console.log(URL.createObjectURL(item))}
<img className="document-image" src={URL.createObjectURL(item)} alt="your file" height="50" width="50"
onClick={() => {
const modal = document.getElementById("myModal");
const modalImg = document.getElementById("img01");
modal.style.display = "block";
modalImg.src = URL.createObjectURL(item);
}}>
</img>
<button className="document-image-deleter" onClick={() => props.deletePreviewfile(item)}>x</button>
<p className="file-name">{item.name}</p>
<p className="file-size">{props.getReadableFileSizeString(item.size)}</p>
</div>
:
// Image - png
item.type === "image/png" ?
<div className="image-file">
{console.log(URL.createObjectURL(item))}
<img className="document-image" src={URL.createObjectURL(item)} alt="your file" height="50" width="50"
onClick={() => {
const modal = document.getElementById("myModal");
const modalImg = document.getElementById("img01");
modal.style.display = "block";
modalImg.src = URL.createObjectURL(item);
}}>
</img>
<button className="document-image-deleter" onClick={() => props.deletePreviewfile(item)}>x</button>
<p className="file-name">{item.name}</p>
<p className="file-size">{props.getReadableFileSizeString(item.size)}</p>
</div>
:
// Others to be added
<div className="image-file">
<img className="document-image" src={URL.createObjectURL(item)} alt="your file" height="50" width="50"
onClick={() => {
const modal = document.getElementById("myModal");
const modalImg = document.getElementById("img01");
modal.style.display = "block";
modalImg.src = URL.createObjectURL(item);
}}>
</img>
<button className="document-image-deleter" onClick={() => props.deletePreviewfile(item)}>x</button>
<p className="file-name">{item.name}</p>
<p className="file-size">{props.getReadableFileSizeString(item.size)}</p>
</div>
}
{/* The Image PopUp */}
<div id="myModal" className="modal">
{/* the close button (x) */}
<span className="close" onClick={() => {
const modal = document.getElementById("myModal");
modal.style.display = "none";
}}>×</span>
{/* the image itself */}
<img className="modal-content" id="img01" alt="Something"></img>
{/* Text needs to be added */}
<div id="caption"></div>
</div>
</li>
)}
</ul>
</div>
)
}
export default FilePreview
这里又是模态的 JSX:
{/* The Image PopUp */}
<div id="myModal" className="modal">
{/* the close button (x) */}
<span className="close" onClick={() => {
const modal = document.getElementById("myModal");
modal.style.display = "none";
}}>×</span>
{/* the image itself */}
<img className="modal-content" id="img01" alt="Something"></img>
{/* Text needs to be added */}
<div id="caption"></div>
</div>
这里是添加transform/translate 属性拖拽聊天上传预览的功能。它似乎是模态奇怪行为的罪魁祸首,因为当我删除它时,模态再次表现良好。
componentDidUpdate () {
if (this.myUploader.current) {
this.myUploader.current.style.transform = `translate(${this.state.position.x}px, ${this.state.position.y}px)`
document.onmouseup = () => {this.setState({pressed: false})}
}
}
这是聊天上传预览的(父组件)CSS:
.chat-upload-preview-1 {
position: absolute;
bottom: 30px;
left: 300px;
background-color: blanchedalmond;
width: 330px;
height: 600px;
border-radius: 20px;
opacity: 0.9;
}
这是模态的 css:
/* The Modal (background) */
.modal {
display: none; /* Hidden by default */
position: fixed; /* Stay in place */
z-index: 1; /* Sit on top */
padding-top: 100px; /* Location of the box */
left: 0;
top: 0;
width: 100%; /* Full width */
height: 100%; /* Full height */
overflow: auto; /* Enable scroll if needed */
background-color: rgb(0, 0, 0); /* Fallback color */
background-color: rgba(0, 0, 0, 0.9); /* Black w/ opacity */
}
/* Modal Content (image) */
.modal-content {
margin: auto;
display: block;
width: 80%;
max-width: 700px;
}
/* Caption of Modal Image */
#caption {
margin: auto;
display: block;
width: 80%;
max-width: 700px;
text-align: center;
color: #ccc;
padding: 10px 0;
height: 150px;
}
/* Add Animation */
.modal-content,
#caption {
-webkit-animation-name: zoom;
-webkit-animation-duration: 0.6s;
animation-name: zoom;
animation-duration: 0.6s;
}
@-webkit-keyframes zoom {
from {
-webkit-transform: scale(0);
}
to {
-webkit-transform: scale(1);
}
}
@keyframes zoom {
from {
transform: scale(0);
}
to {
transform: scale(1);
}
}
我只是不知道一旦上传预览添加了 transform/translate 属性 模态框会发生什么。为什么它不会像添加 transform/translate 属性 之前那样充分扩展?我完全不解。
所以,我自己找到了答案。答案在关于转换的 MDN 文章中:https://developer.mozilla.org/en-US/docs/Web/CSS/transform
答案:如果变换 属性 的值不同于 none,将创建一个堆叠上下文。在这种情况下,该元素(具有变换 属性 的元素)将充当任何位置的包含块:固定;或位置:绝对;它包含的元素(模态div)。
问题确实出在转换 CSS 函数中。事实证明,Transform 将可拖动元素更改为一个包含块,该块将其内部的所有元素限制在其尺寸限制内。换句话说,所有内部元素都不会大于它的高度或宽度。
更具体地说,Modal div 没有展开以填满整个屏幕,因为变换 属性 是在拖动时添加到 FilePreview 组件的。结果,image-preview-container div(父元素)成为模态 div(子元素)的包含块,将其限制在其 limits/margins.[=11= 内]
因此,解决方法是在单击图像时从包含块中删除变换 属性,以便它可以像以前一样填满整个屏幕:
if (props.myUploader) { props.myUploader.current.style.transform = 'none' }