Safari浏览器二次调用window.print()异常问题求助
问题分析与解决方案
我之前也踩过Safari里window.print()的类似坑,结合你的代码来看,问题大概率出在这几个地方:
核心原因
- 重复iframe名称引发的引用冲突:你每次创建的iframe都用了固定的
name="frame3",虽然最后会把它从DOM里移除,但Safari的window.frames集合可能还残留着对旧iframe的引用。第二次点击时,window.frames["frame3"]可能指向的是已经被销毁的iframe实例,这时候调用print()自然没反应。 - 文档加载状态未确认:直接写完HTML就调用
close,然后靠固定500ms的setTimeout执行打印,这个时间在不同设备或Safari版本里不一定够,第二次操作时可能文档还没完全渲染好,导致print触发异常。
修复后的代码示例
我调整了你的代码,针对性解决了上面的问题:
$scope.print = function() { var contents = document.getElementById("print-section").outerHTML; // 生成唯一的iframe名称,彻底避免重复冲突 var frameName = "print-frame-" + Date.now(); var frame1 = document.createElement('iframe'); frame1.name = frameName; frame1.style.position = "absolute"; frame1.style.top = "-1000000px"; document.body.appendChild(frame1); // 简化frame文档的获取逻辑,兼容不同浏览器 var frameDoc = frame1.contentDocument || frame1.contentWindow.document; frameDoc.open(); frameDoc.write('<html><head>'); // 这里可以添加打印专属的样式或脚本,比如: // frameDoc.write('<link rel="stylesheet" href="print-styles.css">'); frameDoc.write('</head><body>'); frameDoc.write(contents); frameDoc.write('</body></html>'); frameDoc.close(); // 监听iframe的load事件,确保文档完全加载后再执行打印 frame1.onload = function() { frame1.contentWindow.focus(); frame1.contentWindow.print(); // 监听打印完成事件,再移除iframe(适配Safari的异步打印逻辑) function handlePrintFinish() { document.body.removeChild(frame1); frame1.contentWindow.removeEventListener('afterprint', handlePrintFinish); } frame1.contentWindow.addEventListener('afterprint', handlePrintFinish); }; return false; };
额外注意点
- 放弃固定名称的iframe,用时间戳或随机字符串生成唯一标识,从根源解决引用冲突问题。
- 用
onload事件替代固定延迟的setTimeout,确保文档完全渲染后再执行打印,比硬写延迟更可靠。 - 利用
afterprint事件在打印完成后再移除iframe,避免Safari在打印过程中丢失iframe引用。
内容的提问来源于stack exchange,提问作者paul590
相关产品推荐
相关产品推荐

