遭遇'Uncaught TypeError: Cannot read properties of null (reading 'contentDocument')'错误求助
问题排查:iframe未加载导致的
Cannot read properties of null错误 我参考了Stack Overflow上的《How to check if iframe is loaded or it has a content?》解决方案,但持续遇到错误:Uncaught TypeError: Cannot read properties of null (reading 'contentDocument')。我已确认iframe的ID正确,该iframe由.vzPlayer内的脚本在.voiceDemos容器中创建。运行代码后控制台仅打印出000000000000,后续日志无输出,isMobile已定义为false。
相关代码
<div class="vzPlayer"> <script> var CSS_THEME = "//voicezam.com/CSPlayer/style/Headless.css" /* Enter your account ID. You can find this under the Menu item: Help | About */ var ACCOUNT_ID = 'REDACTED'; /* Enter the title of this page. All events will appear in your Zamtistics */ var PAGE_NAME = 'Demos page for REDACTED'; /* The value of RENDER_MODE may be either 'inline' (default) OR 'popup' */ var RENDER_MODE = 'inline'; /* The DEFAULT_DEMO value may be:*/ /* null - (default) - Display the top Demo as listed in your Showcase */ /* xxxx - (Demo Category ID) - Display this Demo when the player launches */ /* note: The Category ID is listed under the Demo's gear icon with in your Showcase */ /* 0 - Displays the Player's Demo playlist when the player launches */ /* note: Demos are listed in the order defined within your Showcase */ var DEFAULT_DEMO = null; /* (default); */ /* If presenting on mobile device, use vertical player and offer Category playlist */ if (document.getElementsByClassName("vzCodeBlock")[0].offsetWidth <= 600) { DEFAULT_DEMO = 0; PLAYER_STYLE = '03'; } /* Option to show Contacts panel in player */ var SHOW_CONTACTS = true; </script> <script src="//www.voicezam.com/clientScripts/WebLinking2.aspx"></script> <div id="voiceDemos" style="width:100%; height:324px"></div> <!-- Note: Optional codeline below asserting player <DIV> at 100% --> <!-- <div id="voiceDemos" style="width:100%;"></div> --> </div> <script> var isMobile = false; //initiate as false // device detection if(/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|ipad|iris|kindle|Android|Silk|lge |maemo|midp|mmp|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino/i.test(navigator.userAgent) || /1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(navigator.userAgent.substr(0,4))) { isMobile = true; } function checkIframeLoaded() {console.log('000000000000'); // Get a handle to the iframe element var iframe = document.getElementById('ZAMPLAYER_IFRAME_MEDIAZAM'); var iframeDoc = iframe.contentDocument || iframe.contentWindow.document; console.log('1111111111111'); // Check if loading is complete if ( iframeDoc.readyState == 'complete' ) {console.log('22222222222'); // The loading is complete, call the function we want executed once the iframe is loaded afterLoading(); return; } // If we are here, it is not loaded. Set things up so we check the status again in 100 milliseconds console.log('333333333'); window.setTimeout(checkIframeLoaded, 100); } function afterLoading(){console.log('44444444'); document.getElementById("ZAMPLAYER_IFRAME_MEDIAZAM").setAttribute('style','width:777px'); } if(!isMobile){ window.addEventListener('load', function () { checkIframeLoaded(); }); } </script>
问题原因分析
- 核心问题:当
checkIframeLoaded执行时,第三方脚本WebLinking2.aspx还未动态生成目标iframe,导致document.getElementById('ZAMPLAYER_IFRAME_MEDIAZAM')返回null,执行iframe.contentDocument时直接抛出错误,中断了函数后续执行,所以只打印了第一个日志。 - 触发时机问题:
window.load事件仅等待页面初始静态资源加载完成,但第三方脚本可能在window.load事件触发后才开始创建iframe,你的代码执行早于iframe的生成时间。
解决方案
方案1:增加iframe存在性检查(快速修复)
修改checkIframeLoaded函数,先确认iframe是否存在,再进行后续操作,避免直接报错:
function checkIframeLoaded() { console.log('000000000000'); var iframe = document.getElementById('ZAMPLAYER_IFRAME_MEDIAZAM'); // 先检查iframe是否已被创建 if(!iframe){ console.log('iframe尚未创建,等待重试'); window.setTimeout(checkIframeLoaded, 100); return; } var iframeDoc = iframe.contentDocument || iframe.contentWindow.document; console.log('1111111111111'); if (iframeDoc.readyState == 'complete') { console.log('22222222222'); afterLoading(); return; } console.log('333333333'); window.setTimeout(checkIframeLoaded, 100); }
方案2:监听容器DOM变化(更可靠)
使用MutationObserver监听voiceDemos容器,当iframe被插入时再开始检查加载状态,避免无效轮询:
if(!isMobile){ window.addEventListener('load', function () { const targetContainer = document.getElementById('voiceDemos'); const observer = new MutationObserver((mutations) => { mutations.forEach(mutation => { if(mutation.addedNodes.length > 0){ const iframe = document.getElementById('ZAMPLAYER_IFRAME_MEDIAZAM'); if(iframe){ observer.disconnect(); // 找到iframe后停止监听 checkIframeLoaded(); } } }); }); // 监听容器的子节点变化 observer.observe(targetContainer, { childList: true, subtree: true }); }); }
方案3:直接绑定iframe的load事件(推荐)
如果能确保iframe生成后可绑定事件,直接监听其load事件,无需轮询:
function setupIframeListener() { const iframe = document.getElementById('ZAMPLAYER_IFRAME_MEDIAZAM'); if(!iframe){ setTimeout(setupIframeListener, 100); return; } // iframe加载完成后直接执行目标函数 iframe.addEventListener('load', afterLoading); } if(!isMobile){ window.addEventListener('load', setupIframeListener); }
内容的提问来源于stack exchange,提问作者DistantDigit
相关产品推荐
相关产品推荐

