如何让iframe内的Modal突破容器限制占满整个屏幕?
问题描述
我开发了一个基于iframe的组件,用户有两种调用方式:
第一种调用方式(外层div限制宽高):
<div style="height: 100px; width: 100px"> <iframe src="https://jade-biscuit-7026ef.netlify.app/?productId=LprOsWjrho5B&type=popup" style="border: 0;" height="100vh" width="100vw"></iframe> </div>
第二种调用方式:
<div style="height: 100vh;"> <iframe src="https://jade-biscuit-7026ef.netlify.app/?productId=LprOsWjrho5B&type=popup" style="border: 0;" height="100%" width="100%"></iframe> </div>
用户可通过外层div设置组件宽高,但目前存在问题:iframe内点击按钮触发的Modal被外层div的尺寸限制,无法占满用户整个屏幕。
以下是iframe内的React组件代码(基于Chakra UI):
/** @format */ import { Modal, ModalOverlay, ModalContent, ModalBody, useDisclosure, Box, } from "@chakra-ui/react"; import CheckoutInfo from "./CheckoutCard"; import { Button } from "mainstack-design-system"; import { useEffect, useState } from "react"; import { TPaymentOptions, TProductDataRes } from "types"; import StripeCardCheckout from "./StripeCardCheckout"; interface IProps { width: string | null; productId: string; btnText?: string; } const PopupCheckout = ({ width, productId, btnText }: IProps) => { const { isOpen, onOpen, onClose } = useDisclosure(); const [openModal,setOpenModal] = useState(false) const [paymentOption, setPaymentOption] = useState<TPaymentOptions>(""); const [productData, setProductData] = useState<TProductDataRes>( {} as TProductDataRes ); const ipAddress = JSON.parse(window.localStorage.getItem("userIp")); const isNigerian = ipAddress?.currency === "NGN"; useEffect(()=>{ setOpenModal(true) },[]) return ( <> <Button variant="primary" onClick={onOpen} label={btnText ?? "Proceed to checkout"} size="medium" /> <Modal isOpen={openModal} onClose={onClose}> <ModalOverlay /> <ModalContent className="modal" borderRadius={'0.75rem'} maxWidth={width} // w={"95%"} // maxH={"90vh"} overflow={"scroll"} > <ModalBody padding={0}> <CheckoutInfo hasBorder hasCancel closeModal={() => setOpenModal(false)} paymentOption={paymentOption} setPaymentOption={setPaymentOption} productId={productId} setProductData={setProductData} /> {paymentOption === "card" && !isNigerian && ( <StripeCardCheckout setPaymentOption={setPaymentOption} productData={productData} closePopup={() => setOpenModal(false)} /> )} </ModalBody> </ModalContent> </Modal> </> ); }; export default PopupCheckout;
解决方案
方法1:同域场景下,将Modal挂载到父页面body
如果iframe与父页面属于同域,可修改Chakra UI Modal的挂载容器,直接将Modal挂载到父页面的document.body上,脱离iframe的尺寸限制:
// 获取父页面的document(仅同域可用) const parentDoc = window.parent.document; <Modal isOpen={openModal} onClose={() => setOpenModal(false)} container={() => parentDoc.body} // 指定Modal挂载到父页面body > {/* 原Modal内容保持不变 */} </Modal>
方法2:动态调整iframe样式(跨域场景推荐)
若存在跨域限制,方法1不可行,可通过监听Modal状态,动态修改iframe的样式,让它在Modal打开时全屏覆盖页面,关闭后恢复原尺寸:
const PopupCheckout = ({ width, productId, btnText }: IProps) => { // 保留原状态定义 const [openModal,setOpenModal] = useState(false) // ...其余状态省略 // 监听Modal状态,动态调整iframe样式 useEffect(() => { const iframe = window.frameElement as HTMLIFrameElement; if (!iframe) return; if (openModal) { // 打开Modal时,设置iframe全屏悬浮 iframe.style.position = "fixed"; iframe.style.top = "0"; iframe.style.left = "0"; iframe.style.width = "100vw"; iframe.style.height = "100vh"; iframe.style.zIndex = "9999"; // 确保Modal处于顶层 iframe.style.border = "0"; } else { // 关闭Modal时,恢复iframe原样式 iframe.style.position = ""; iframe.style.top = ""; iframe.style.left = ""; iframe.style.width = ""; iframe.style.height = ""; iframe.style.zIndex = ""; } }, [openModal]); // 保留原生命周期与按钮逻辑 return ( <> <Button variant="primary" onClick={() => setOpenModal(true)} label={btnText ?? "Proceed to checkout"} size="medium" /> <Modal isOpen={openModal} onClose={() => setOpenModal(false)}> <ModalOverlay /> <ModalContent className="modal" borderRadius={'0.75rem'} maxWidth={width} overflow={"scroll"} > {/* 原ModalBody内容保持不变 */} </ModalContent> </Modal> </> ); };
方法3:调整用户调用方式(依赖用户配置,不推荐)
可告知用户在调用时,给外层div添加overflow: visible,同时将iframe设置为固定定位:
<div style="height: 100px; width: 100px; overflow: visible;"> <iframe src="https://jade-biscuit-7026ef.netlify.app/?productId=LprOsWjrho5B&type=popup" style="border: 0; position: fixed;" height="100vh" width="100vw"></iframe> </div>
内容的提问来源于stack exchange,提问作者Psalms99
相关产品推荐
相关产品推荐

