业务场景
功能:需要在前后端未分离的项目中加载iframe页面
问题:
- 页面首次进入会白屏,第一次之后进入偶现白屏
- iframe内容不会随着通信数据改变而发生变化
部分业务代码
// 父容器代码发送消息代码
resumeDetailIframe.src = url
resumeDetailIframe.onload = () => {
console.log("===========load")
resumeDetailIframe.contentWindow.postMessage({
type: 'isIframe',
currentResumeNo: talentResumeNo,
}, "*")
}
// iframe内接收消息代码
useEffect(() => {
console.log('isEffect','==========effect')
window.addEventListener('message', receiveMessageOnIframe);
return () => {
window.removeEventListener('message', receiveMessageOnIframe)
}
}, [])
排查思路&解决方案
- 因chrome浏览器功能均正常,将浏览器控制台输出的warning&info均做了对比,发现并无不同
由此推测:浏览器对iframe的加载机制有差异。 - 写log&打断点调试
第一个问题:发现在火狐浏览器中log输出顺序
// 白屏
console.log("===========load")
console.log('isEffect','==========effect')
// 可正常展示
console.log('isEffect','==========effect')
console.log("===========load")
由此推测:
父容器在load的时候发送消息过去,但因为iframe那边还未加载完成,所以也就未收到展示消息,导致的想要的内容并未展示。
解决方案:
(1) 增加setTimeout延迟(应证了推测)
var parseData = {
type: 'isIframe',
currentResumeNo: talentResumeNo,
}
setTimeout(()=>{
resumeDetailIframe.contentWindow.postMessage(parseData, "*")
},200)
(2) 在iframe加载完成之后通知父容器,可以发送消息了。父容器在接收到发送消息指令后,发送相关消息,这样即可保证消息传输可被接收到。
useEffect(() => {
window?.parent?.postMessage({
type: 'please-send-info',
message: '可发送消息过来'
}, '*')
}, [])
第二个问题:iframe内容不更新,在log中发现
chrome浏览器:在每次onload均会走一遍方法。
火狐浏览器:在第一次之后onload的方法不会再执行,因为我们发送消息代码均放在onload中,所以不会被执行。
解决方案:
var parseData = {
type: 'isIframe',
currentResumeNo: talentResumeNo,
}
var isIframeLoaded = false
if(!isIframeLoaded){
resumeDetailIframe.src = url;
resumeDetailIframe.onload = () => {
setTimeout(()=>{
resumeDetailIframe.contentWindow.postMessage(parseData, "*")
},200)
isIframeLoaded=true
}
}else{
setTimeout(()=>{
resumeDetailIframe.contentWindow.postMessage(parseData, "*")
},200)
}
🎉🎉🎉