Vue中绑定@load的iframe load事件触发两次的原因及规避方法
问题原因解析
结合示例代码逐行梳理,两次触发load事件是固定逻辑导致的可复现问题,不存在Vue框架或浏览器的随机bug:
- 你给iframe使用
v-show做显隐控制,而非v-if的DOM销毁重建逻辑,这意味着只要外层webviewOpen状态为true,iframe元素就会立刻被插入DOM树,根本不等你1秒后把showIframe置为true。 - 浏览器对iframe有固定的加载规则:当iframe刚被插入DOM时,会先瞬时加载
about:blank空页面,哪怕你已经给src绑定了真实业务地址,这个空页的加载流程也会先跑一遍,直接触发第一次load事件——这就是你感知到的“元素刚创建就触发回调”的来源。 - 等浏览器解析到iframe绑定的真实
src地址、完成对应资源加载后,会触发第二次load事件。 - 你之前用setTimeout延迟修改
showIframe的操作完全起不到拦截作用:v-show只是修改CSS的display属性把iframe视觉上隐藏,已经存在于DOM的iframe哪怕不可见,浏览器也会按照绑定的src属性正常发起请求、触发load回调,元素是否可见和是否发起资源请求没有关系。
可落地的解决方案
方案1:从根源上减少无效触发
把iframe的v-show改成v-if,等真正需要加载真实资源的时候再把iframe插入DOM,从流程上消除about:blank空页触发的无效回调:
<!-- 替换原有的v-show绑定逻辑 --> <iframe v-if="showIframe" :src="webviewUrl" @load="iframeIsLoaded" />
修改后iframe只有在showIframe置为true的时刻才会被创建,此时DOM和绑定属性已经完成初始化,只会触发一次和真实资源加载对应的load事件,没有多余触发。
方案2:在回调层做无效事件过滤
如果因为业务逻辑必须保留v-show的写法,可以在load回调里判断当前触发事件对应的加载地址,直接过滤掉空页触发的无效回调:
iframeIsLoaded (e) { // 跳过about:blank空页触发的无效回调 if (e.target.src === 'about:blank') return // 此处仅执行真实资源加载完成后的业务逻辑 console.log('iframe 加载完成') }
方案3:延后绑定真实src属性
如果不想改动原有显隐逻辑,可以调整src的绑定时机:一开始iframe插入DOM时不绑定真实src,等空页的load事件触发完成后,再动态给src赋值真实业务地址。这种方式虽然还是会触发两次load,但两次触发的时机完全可控,你可以在第二次回调里执行真正的业务逻辑。
内容的提问来源于stack exchange,提问作者drake035
相关产品推荐
相关产品推荐

