仅Safari出现:Vue组件中Iframe加载SSO时隔次打开新tab问题
问题根因
- 该问题是Safari浏览器特有的DOM节点缓存机制导致的:组件卸载时,Safari不会主动清理iframe的
name属性全局注册记录,当组件二次挂载时,新的iframe和旧的残留记录重名,表单提交时无法正确匹配到当前页面的iframe target,就会默认触发新标签页打开行为,第三次挂载时旧的残留记录刚好被GC回收,所以表现为隔一次复现的规律。 - 异步获取SSO信息后调用
$nextTick的时机在Safari下无法100%保证iframe已经完成挂载渲染,也会加重target匹配失败的概率。
修复方案
修改后的完整代码如下:
<template> <div> <form :action="endPoint" :target="iframeName" ref="ssoForm" method="POST" name="ssoForm" id="ssoForm" > <input id="AuthCode" type="hidden" name="AuthCode" :value="authorizationCode" /> <input id="AuthAppUrl" type="hidden" name="AuthAppUrl" :value="authAppUrl" /> </form> <iframe width="100%" :name="iframeName" height="300" style="display: flex" :id="iframeName" frameborder="0" ref="ssoIframe" ></iframe> </div> </template> <script> import types from "path/to/types" export default { data() { return { endPoint: null, authorizationCode: null, authAppUrl: null, errorStatus: false, error: null, // 每次挂载生成唯一的iframe name,避免和残留记录重名 iframeName: `the_iframe_${Date.now()}_${Math.random().toString(36).slice(2)}` } }, methods: { async getSSOModel() { try { var data = await this.$store.dispatch( `store/${types.GET_SSO_MODEL}` ) this.endPoint = data.endPoint this.authorizationCode = data.authorizationCode this.authAppUrl = data.authAppUrl await this.$nextTick() // 提交前主动确认iframe节点已存在 if (this.$refs.ssoIframe && this.$refs.ssoForm) { this.$refs.ssoForm.submit() } } catch (error) { this.error = error this.errorStatus = true } } }, async mounted() { await this.getSSOModel() }, beforeUnmount() { // 组件卸载前主动清理iframe内容,避免Safari缓存残留 if (this.$refs.ssoIframe) { this.$refs.ssoIframe.src = 'about:blank' this.$refs.ssoIframe.remove() } if (this.$refs.ssoForm) { this.$refs.ssoForm.remove() } } } </script>
修复逻辑说明
- 每次组件挂载时生成唯一的iframe name值,彻底避开Safari的同名target缓存问题
- 增加生命周期钩子主动销毁iframe和表单节点,清空iframe内容,主动触发Safari的缓存清理
- 提交表单前增加节点存在校验,避免异步逻辑导致的节点未挂载就提交的问题
- 如果使用Vue2开发,将代码中的
beforeUnmount生命周期钩子替换为beforeDestroy即可生效
内容的提问来源于stack exchange,提问作者Jim's Code Corner
相关产品推荐
相关产品推荐

