Chrome 72.0.3626.96中<input type="file">触发异常问题及解决方案
Chrome 72.0.3626.96 中 confirm() 延迟确认无法触发文件选择框的问题解决
你遇到的这个问题确实和Chrome的User Activation安全机制更新直接相关。Chrome从该版本开始,严格限制了用户交互上下文的有效期:当用户触发一个主动交互(比如点击按钮)后,对应的权限上下文会在短时间内失效。而原生confirm()对话框如果等待过久才确认,就会超出这个有效期,导致后续触发文件选择框的操作被浏览器判定为「非用户主动触发」而拦截。
问题原因详解
Chrome的User Activation机制要求,像弹出文件选择框这类涉及用户隐私的操作,必须在用户主动触发的即时上下文中执行。原生confirm()是阻塞式弹窗,但浏览器会把从点击按钮到确认对话框的等待时间排除在有效交互上下文之外。如果等待2-4秒,上下文已经过期,trigger('click')就会被安全机制拦截。
解决方案
方案1:用Bootstrap模态框替代原生confirm()(推荐长期方案)
正如你已经尝试的,用Bootstrap的自定义模态框代替原生confirm()是最可靠的解决方式。因为模态框的「确认」按钮点击是一个全新的用户主动交互,完全处于有效的用户激活上下文内,不会出现过期问题。
完整实现代码如下:
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.0/css/bootstrap.min.css" rel="stylesheet"/> <link href="https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet"/> <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.0/umd/popper.min.js"></script> <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.0/js/bootstrap.min.js"></script> <style> #upload-file { display: none; } </style> <div class="container"> <div class="row"> <div class="col"> <a id="upload-button" class="btn btn-primary"> <span>Upload Something!</span> </a> <input type="file" id="upload-file"> </div> </div> </div> <!-- 确认模态框 --> <div class="modal fade" id="upload-confirm-modal" role="dialog"> <div class="modal-dialog"> <div class="modal-content"> <div class="modal-body"> <h4>Are you sure?</h4> </div> <div class="modal-footer"> <button type="button" class="btn btn-default" data-dismiss="modal">No</button> <button type="button" class="btn btn-primary" id="upload-confirm-button">Yes</button> </div> </div> </div> </div> <script> $('#upload-button').on('click', function() { $('#upload-confirm-modal').modal(); }); $('#upload-confirm-button').on('click', function() { $('#upload-file').trigger('click'); $('#upload-confirm-modal').modal('hide'); }); </script>
方案2:临时 workaround(不推荐长期使用)
如果你暂时不想替换原生confirm(),可以尝试在用户点击按钮的瞬间,先触发一次文件选择框的click事件(立即取消),以此延长用户激活上下文的有效期。不过这个方法依赖浏览器的具体实现,稳定性较差:
$('#upload-button').on('click', function(e) { // 提前触发一次,保留激活上下文 $('#upload-file').trigger('click'); if (confirm('Are you sure?')) { $('#upload-file').trigger('click'); } });
是否需要提交Bug?
这个不属于Chrome的合法Bug,而是Chrome为了规范安全交互做出的机制调整。原生confirm()的阻塞特性与新的用户激活机制冲突是预期内的行为,官方更推荐使用非阻塞的自定义模态框来实现这类交互逻辑。
内容的提问来源于stack exchange,提问作者B. Humphries




