React resizable-iframe导致在释放鼠标并达到minConstraints时不停止调整大小



我在项目中使用react resizable。我有一个可调整大小的框,我在其中设置了minConstraints道具。我的问题是,当调整方框大小并达到minConstraints时,在我释放鼠标按钮后,它仍然会继续调整方框大小,如果我向相反方向移动鼠标,它会使其变大,因为它仍然在跟踪鼠标的移动。

如果我反其道而行之,按住鼠标调整方框大小,使其变大,释放鼠标后,由于我释放了鼠标,方框将不会调整大小。我如何解决这个问题,并在到达minConstraints时也有同样的行为?

这就是组件:

function PaperComponent({ x, y, setX, setY, ...props }) {
return (
<Draggable
position={{ x: x, y: y }}
cancel={".react-resizable-handle"}
onDrag={(e) => {
if (e.movementX !== 0) {
setX((prev) => prev + e.movementX);
}
if (e.movementY !== 0) {
setY((prev) => prev + e.movementY);
}
}}
>
<Paper {...props} />
</Draggable>
);
}
const StyledDialog = withStyles({
root: {
pointerEvents: "none"
},
paper: {
pointerEvents: "auto"
},
scrollPaper: {
display: "flex",
alignItems: "center",
justifyContent: "flex-end",
marginRight: 20
}
})((props) => <Dialog hideBackdrop {...props} />);
const useStyles = makeStyles({
dialog: {
cursor: "move"
},
dialogContent: {
"&:first-child": {
padding: 10,
background: "white"
}
},
clearIcon: {
position: "absolute",
top: -20,
right: -20,
background: "white",
zIndex: 1,
"&:hover": {
background: "white"
}
},
paper: {
overflowY: "visible",
maxWidth: "none",
maxHeight: "none"
},
resizable: {
position: "relative",
"& .react-resizable-handle": {
position: "absolute",
width: 20,
height: 20,
bottom: 0,
right: 0,
background:
"url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA2IDYiIHN0eWxlPSJiYWNrZ3JvdW5kLWNvbG9yOiNmZmZmZmYwMCIgeD0iMHB4IiB5PSIwcHgiIHdpZHRoPSI2cHgiIGhlaWdodD0iNnB4Ij48ZyBvcGFjaXR5PSIwLjMwMiI+PHBhdGggZD0iTSA2IDYgTCAwIDYgTCAwIDQuMiBMIDQgNC4yIEwgNC4yIDQuMiBMIDQuMiAwIEwgNiAwIEwgNiA2IEwgNiA2IFoiIGZpbGw9IiMwMDAwMDAiLz48L2c+PC9zdmc+')",
backgroundPosition: "bottom right",
padding: 3,
backgroundRepeat: "no-repeat",
backgroundOrigin: "content-box",
backgroundSize: "cover",
boxSizing: "border-box",
cursor: "se-resize"
}
},
iframe: {
position: "absolute",
top: 0,
left: 0,
bottom: 0,
right: 0,
padding: 20
}
});
function PDFDialog() {
const classes = useStyles();
const [open, setOpen] = React.useState(true);
const [x, setX] = React.useState(0);
const [y, setY] = React.useState(0);
return (
<StyledDialog
open={open}
classes={{ root: classes.dialog, paper: classes.paper }}
PaperComponent={PaperComponent}
aria-labelledby="draggable-dialog"
PaperProps={{
x: x,
y: y,
setX: setX,
setY: setY
}}
>
<ResizableBox
height={520}
width={370}
minConstraints={[370, 520]}
maxConstraints={[Infinity, Infinity]}
className={classes.resizable}
onResize={(e) => {
if (e.movementX !== 0) {
setX((prev) => prev + e.movementX);
} else if (e.movementY !== 0) {
setY((prev) => prev + e.movementY / 2);
}
}}
>
<DialogContent
classes={{ root: classes.dialogContent }}
id="draggable-dialog"
>
<IconButton
className={classes.clearIcon}
aria-label="Clear"
onClick={() => setOpen(false)}
>
<ClearIcon />
</IconButton>
<iframe
className={classes.iframe}
src="http://www.orimi.com/pdf-test.pdf"
title="PDF test file"
width="100%"
height="100%"
></iframe>
</DialogContent>
</ResizableBox>
</StyledDialog>
);
}
export default PDFDialog;

这是代码沙盒。

似乎是iframe造成了问题。如果我在它上设置了z-index: -1,那么它的行为就会正常。但是,我遇到了无法在iframe中滚动的问题。我该怎么解决?

与z-index修复程序一样,在iframe上设置pointerEvents: 'none'似乎也可以缓解问题,但它可能也存在同样的无滚动问题。(我不能肯定。iframe内容实际上并没有在沙盒中为我加载。(

问题似乎是,停止拖动行为的mouseup事件发生在视口之外(因为iframe(,所以跟踪拖动的东西永远不会收到它,也不知道该停止。

一个潜在的解决方案是在拖动开始时在document上注册一个mouseout侦听器,该侦听器手动触发mouseup事件以停止拖动。

这需要一些调整——如果你拖得太快,它就会过早地启动——但这里有一个沙盒分叉中的概念验证。

您可以通过setTimeout或查看是否达到了约束限制来修复过早停止。我还没有完全考虑清楚,但我认为这是可以解决的。

onResize = {(e) => {
// handler for when the mouse exits the active document (enters the iframe)
const onMouseLeave = () => {
// construct a mouseup event…
const event = new MouseEvent("mouseup", { view: window, bubbles: true, cancelable: true });
// …and dispatch it
document.dispatchEvent(event);
// remove the listener since we're not dragging anymore
document.removeEventListener("mouseout", onMouseLeave);
};
// register the mouseleave handler above
document.addEventListener("mouseout", onMouseLeave);
// continue with whatever else you're already doing
if (e.movementX !== 0) {
setX((prev) => prev + e.movementX);
} else if (e.movementY !== 0) {
setY((prev) => prev + e.movementY / 2);
}

后记:

  1. 这似乎是react draggable中的一个bug。如果你找到了一个可靠的解决方案,你可以考虑提交一份公关
  2. 每次渲染时,你的应用程序中都会有一些东西偷走焦点,这使得在代码沙盒中进行编辑变得非常烦人。😆
  3. 您可能不需要从onResize处理程序内部添加侦听器。在装载或其他方面处理它可能更高效、更易于维护。再说一遍,我还没有真正彻底考虑过这一点

问题似乎是由iframe引起的。如果我将z索引设置为-1它,那么它就表现得像它应该做的那样。但是,我的问题是能够在iframe中滚动。我该怎么解决?

由于它的行为与您在将z-index: -1CSS属性添加到iframe时所提到的一样,所以只要在开始调整大小时添加该CSS属性,并在停止调整大小时将其删除即可!

以下相关代码:

function PDFDialog() {
const [resizeInProgress, setResizeInProgress] = React.useState(false);
const iFrameStyle = {
zIndex: -1 // simply add this when you start the resizing process
};
return (
<ResizableBox
onResizeStart={() => setResizeInProgress(true)}
onResizeStop={() => setResizeInProgress(false)}
>
<iframe
style={resizeInProgress ? iFrameStyle : {}}
></iframe>
</ResizableBox>
)
}

最新更新