iframe 弹窗取消按钮触发父页面弹窗接口

iframe 弹窗取消按钮触发父页面新增弹窗接口

在开发中,我们可能会因为一些需要需要调用弹窗,进而需要进行父子组件间的通信,但iframe弹窗的新建和销毁又必然会伴随着很多其他的问题,而我最近也遇到了一个关于弹窗销毁带来的一些问题

bug复现

我们的业务需求是在父页面新增一个方法打开一个子页面弹窗,在子页面窗口进行一系列操作然后关闭弹窗,其中我们在关闭子页面弹窗的时候,后台服务器会接收到前端父页面发来的新增弹窗的接口请求,现在我们需要解决这一无端请求的发送问题

父页面打开弹窗的方法

javascript 复制代码
    //回调方法  子页面可以直接对父页面进行操作的回调函数
    window.parent.callback = function (mes) {
        $('#bootstrap-tree-table').bootstrapTable('refresh');
        var layer = layui.layer;
        var index = layer.load(2, {time: 10 * 1000}); //又换了种风格,并且设定最长等待10秒
        setTimeout(function () {
            layer.msg(mes, {icon: 1});
            epoPage.loadData();
            workNum();
        }, 1000)
    };


$(".staffAdd").click(function () {
        window.parent.layer.open({
            type: 2,
            title: false,
			shade:0.2, /*增加遮罩,阻断点击穿透*/
            area: ['55%', '70%'],
            content: '/page/staffAdd'
        });
    })

子页面弹窗以及关闭弹窗

HTML层

html 复制代码
<form class="layui-form" action="" autocomplete="off" id="form">
        <div class="staff-add-action">
            <button class="layui-btn layui-btn-lg save" onclick="sub()" type="button">保存</button>
            <button class="layui-btn layui-btn-primary layui-btn-lg cancel">取消</button>
        </div>
    </form>

JavaScript层

javascript 复制代码
<script th:inline="javascript">
    sub = function () {
            $.ajax({
                url: "/staff/add",
                type: "post",
                dataType: "json",
                data: data,
                success: function (res) {
                    layer.close(loading);
                    if (res.success) {
                        var index = parent.layer.index;
                        parent.callback(res.msg); //调用父页面的回调函数
                        var temp = window.parent.layer.close(index);
                    } else {
                        layer.msg(res.msg);
                    }
                }
            })
        }
        $(".save").attr("readonly", false);
    }

    $(".cancel").click(function () {
        var index = parent.layer.index;
        parent.layer.close(index);
    })
</script>

在这个代码运行的页面当我们点击取消按钮,则父页面会向后端传递 /page/staffAdd 这个打开页面弹窗的请求

解决方案

bug类别

大分类上属于前端 DOM 事件类 Bug

细分属于事件逃逸(Event leakage /event escape) + HTML 表单默认行为陷阱 + iframe 上下文销毁副作用

行业口语叫法:

iframe 销毁事件逃逸 bug(layer iframe 高频坑)

form 内 button 缺少type="button"默认 submit 踩坑

同步销毁 DOM / iframe 导致未完成 DOM 事件异常冒泡逃逸

css 复制代码
注意:这个不是 JS 代码逻辑错误,是HTML 原生默认行为 + 浏览器 DOM 生命周期机制共同叠加出来的复合坑,不是框架 bug,属于开发者对浏览器默认行为理解不足引入的缺陷。

原因拆解

less 复制代码
1.HTML 原生缺陷条件:<form>内的<button>省略 type 属性,浏览器默认 type="submit"。点击按钮会原生触发表单 submit 事件,这是 HTML 标准规定,很多开发者不知道这个默认值。

注:很多人误以为 button 默认是普通按钮,实际 form 标签内部 button 默认是提交按钮。

2.时序缺陷条件:在 click 事件回调里面同步直接执行parent.layer.close(index)立刻销毁 iframe;此时浏览器 DOM 事件冒泡、事件处理流程还没有执行完毕,iframe DOM、JS 上下文直接被浏览器回收。

3.浏览器机制副作用条件:iframe 被销毁后,还在事件队列中未处理完的原生 DOM 事件失去宿主上下文,事件对象 target 错乱,事件向上逃逸到顶层父页面 window;父页面用$(document).on()全局事件委托,匹配到选择器,错误执行父页面回调

总结:三个条件叠加,才出现:点子页面取消,结果执行父页面打开弹窗的逻辑。仅仅缺 type 只会发生子页面表单提交;如果不立刻同步销毁 iframe,事件不会逃逸到父页面。

解决方案

HTML规范

form 表单内部,所有非提交按钮强制写 type 属性

bash 复制代码
提交按钮:<button type="submit">保存</button>

普通按钮 / 取消 / 重置:<button type="button">取消</button>
禁止 form 内部出现不带 type 的裸 button。
html 复制代码
<!-- form表单规范示例 -->
<form class="layui-form" action="" autocomplete="off" id="form">
        <div class="staff-add-action">
            <button class="layui-btn layui-btn-lg save" onclick="sub()" type="button">保存</button>
            <button class="layui-btn layui-btn-primary layui-btn-lg cancel" type="button">取消</button>
        </div>
    </form>

JS 时序规范

bash 复制代码
不要在 DOM 事件回调中同步销毁当前事件所在的 DOM/iframe。
把销毁 / 移除操作丢到下一轮事件循环,使用setTimeout(fn, 0~30),让浏览器把当前 click/submit 事件完整走完,再销毁 DOM。
javascript 复制代码
// 错误:同步销毁,事件还没跑完
parent.layer.close(index);
// 正确:等事件循环完成后再销毁
setTimeout(()=> parent.layer.close(index), 20);
javascript 复制代码
// 取消按钮事件,延时关闭iframe
$(".cancel-btn").on("click", function (e) {
    e.preventDefault();
    let index = parent.layer.getFrameIndex(window.name);
    // 延时执行关闭,避免事件逃逸
    setTimeout(() => {
        parent.layer.close(index);
    }, 20);
});
相关推荐
勾勾圈圈蛋蛋1 小时前
黑马Vue_day12(一):getters,怎么看 Apifox 文档,工程化等工具介绍;
前端
参宿71 小时前
像素vs条数级虚拟列表
前端
paopaokaka_luck2 小时前
基于springboot3+vue3的云南本土影视文旅推荐平台(协同过滤算法、Echarts图形化分析)
前端·spring boot·学习·算法·echarts·mybatis
狂师2 小时前
AI 测试提效 | 别搞万能 Skill,推荐用 5 个 Agent Skill 串起 UI 自动化全流程
前端·人工智能·测试
breeze jiang2 小时前
React useRef 实战:从 input 聚焦到 Web Worker 引用
前端·javascript·react.js
90后的晨仔3 小时前
uni-app 生命周期深度解析(iOS / Android / 鸿蒙 / Vue3 四端对照)
前端
钛态4 小时前
AI 辅助:前端框架反模式:过度封装、状态滥用与副作用失控
前端·vue·react·web
by__csdn4 小时前
Vue vs React vs Angular:前端框架终极对决
前端·vue.js·react.js·前端框架·vue·react·angular