iframe添加addEventListener无效、获取Iframe的contentWindow和contentDocument失败,不使用postMessag,如何监听iframe点击事件

提示:


前言

需求:点击页面非弹窗区域,关闭弹窗,

问题:全局添加点击监听事件window.addEventListener(‘click’,()=>{console.log(‘点击页面!’)});,无法监听iframe被点击。

方案1:给iframe添加addEventListener
失败原因:无效

	let TestIframe = document.getElementById('TestIframe');
    TestIframe.addEventListener('click',()=>{console.log('iframe点击!')});

方案2:给iframe.contentDocument添加addEventListener
失败原因:谷歌浏览器更新后,无法获取iframe.contentWindow和iframe.contentDocument

	let TestIframe = document.getElementById('TestIframe');
    TestIframe.contentWindow.addEventListener('click',()=>{console.log('contentWindow点击!')});

在这里插入图片描述
方案3:使用postMessage
缺点:1、每个iframe都需要添加postMessage,2、部分iframe嵌套外部项目,无法进行postMessage添加。

方案4:监听iframe是否为当前document的activeElement,activeElement 属性返回文档中当前获得焦点的元素。
解决方案:通过全局点击事件监听和iftame监听activeElement,可实现页面点击监听


示例未作单独处理,正常情况下,打开弹窗,开启定时器setInterval,关闭弹窗,清除定时器clearInterval。


一、全局点击事件,无法监听iframe被点击。

浏览器同源策略,不然会报错
在这里插入图片描述
a.html

	<!DOCTYPE html>
		<html lang="en">
		<head>
		    <meta charset="UTF-8">
		    <meta name="viewport" content="width=device-width, initial-scale=1.0">
		    <title>a</title>
		    <style>
		        .a_box{
		            height: 600px;
		            width: 600px;
		            background-color: #f00;
		            position: relative;
		        }
		        .a_inner{
		            position: absolute;
		            top: 50px;
		            left: 50px;
		            height: 500px;
		            width: 500px;
		            background: #000;
		        }
		    </style>
		</head>
		<body>
		    <div class="a_box">
		        <div class="a_inner">
		            <iframe id="TestIframe" height="100%" width="100%" src="http://127.0.0.1:5500//b.html" frameborder="0"></iframe>
		        </div>
		    </div>
		    <script>
		        window.addEventListener('click',()=>{console.log('点击页面!')});
		    </script>
		</body>
		</html>

b.html

	<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>b</title>
    <style>
        .b_box{
            height: 400px;
            width: 400px;
            background-color: #ff0;
            position: absolute;
            top: 50px;
            left: 50px;
        }
    </style>
</head>
<body>
    <div id="bBox" class="b_box"></div>
</body>
</html>

二、解决方案

1、a.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>a</title>
    <style>
        .a_box{
            height: 600px;
            width: 600px;
            background-color: #f00;
            position: relative;
        }
        .a_inner{
            position: absolute;
            top: 50px;
            left: 50px;
            height: 500px;
            width: 500px;
            background: #000;
        }
    </style>
</head>
<body>
    <div class="a_box">
        <div class="a_inner">
            <iframe id="TestIframe" height="100%" width="100%" src="http://127.0.0.1:5500/b.html" frameborder="0"></iframe>
        </div>
    </div>
    <script>
        window.addEventListener('click',()=>{console.log('点击页面!')});
        let activeElement;
        let iframeCheckTimer = setInterval(()=>{
            if (document.activeElement) {
                if(activeElement==document.activeElement)return
                activeElement=document.activeElement;
                if(activeElement&&activeElement.tagName=='IFRAME'){
                    console.log('iframe被激活');
                }
            }
        },200);
    </script>
</body>
</html>

b.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>b</title>
    <style>
        .b_box{
            height: 400px;
            width: 400px;
            background-color: #ff0;
            position: absolute;
            top: 50px;
            left: 50px;
        }
    </style>
</head>
<body>
    <div id="bBox" class="b_box"></div>
</body>
</html>

点击黑色iframe区域(包括黄色区域),触发iframe监听console.log(‘iframe被激活’)
在这里插入图片描述
点击iframe以为区域(除黑色和黄色),触发全局监听console.log(‘点击页面!’)
在这里插入图片描述

三、试错过程

a.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>a</title>
    <style>
        .a_box{
            height: 600px;
            width: 600px;
            background-color: #f00;
            position: relative;
        }
        .a_inner{
            position: absolute;
            top: 50px;
            left: 50px;
            height: 500px;
            width: 500px;
            background: #000;
        }
    </style>
</head>
<body>
    <div class="a_box">
        <div class="a_inner">
            <iframe id="TestIframe" height="100%" width="100%" src="http://127.0.0.1:5500//b.html" frameborder="0"></iframe>
        </div>
    </div>
    <script>
        let TestIframe = document.getElementById('TestIframe');
        TestIframe.onload = ()=>{
            let contentDocument = TestIframe.contentDocument;
            let bBox = contentDocument.getElementById('bBox');
            bBox.addEventListener('click',()=>{console.log('xxxxxxxxxxxxxxx')})
            console.log(bBox);
        }
    </script>
</body>
</html>

b.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>b</title>
    <style>
        .b_box{
            height: 400px;
            width: 400px;
            background-color: #ff0;
            position: absolute;
            top: 50px;
            left: 50px;
        }
    </style>
</head>
<body>
    <div id="bBox" class="b_box"></div>
</body>
</html>

在这里插入图片描述
在这里插入图片描述
平平无奇的获取iframe内元素,添加点击事件,完美~~
在这里插入图片描述
在这里插入图片描述
但是,但是,但是,在其他版本的谷歌,@_@报错了~~
在这里插入图片描述

总结

踩坑路漫漫长@~@

在 Vue 中,由于 iframe 的内容是在独立沙箱环境中加载的,Vue 本身无法直接监听iframe 内部元素的事件。要解决这个问题,你需要通过一些间接的方式来实现。一种常见的做法是: 1. **通信** (Parent-Child Communication): 使用 Vue 的 `ref` `v-on` 或者自定义事件 (`@custom-event`) 来在父组件iframe子组件之间建立双向数据绑定,然后在父组件上处理点击事件。 ```vue <template> <div> <iframe ref="myIframe" @load="onIframeLoaded"></iframe> <!-- 在这里给 iframecontentDocumentcontentWindow 添加事件 --> <button @click="handleListClick">点击外部按钮</button> </div> </template> <script> export default { methods: { onIframeLoaded() { const iframeDoc = this.$refs.myIframe.contentDocument || this.$refs.myIframe.contentWindow; if (iframeDoc) { const htmlList = iframeDoc.getElementById('your-list-id'); htmlList.addEventListener('click', e => { // 触发你在 iframe 中设置的 click 事件或其他操作 this.$emit('list-item-clicked', e); }); } }, handleListClick(e) { // 在父组件中接收到子组件触发的 'list-item-clicked' 事件并处理 this.$emit('list-item-clicked', { ...e, target: e.target }); }, } } </script> ``` 2. **事件代理** (Event Delegation): 如果 iframe 的元素结构稳定,可以尝试在父级元素上使用事件委托来捕获点击事件,并判断是否来自 iframe。 ```javascript handleListClick(e) { if (e.target.matches('.iframe-selector')) { // 对于匹配到的iframe内的列表项,进行相应的处理 } } ``` 记住,这两种方法都需要对 iframe 内的内容有一定的控制权,并且需要考虑浏览器兼容性问题。如果iframe内容由第三方服务提供,上述方法可能太适用。在这种情况下,你可以考虑与iframe页面的开发者合作,让他们配合提供解决方案。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值