You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

加载外部HTML后操作DOM出现Uncaught TypeError: togBtn is null错误求助

问题原因与解决办法

核心问题

  1. 异步加载未被正确等待:includeHTML内部用异步XMLHttpRequest加载HTML,但函数会立刻返回true——你的Promise刚创建就触发了resolve,此时外部HTML还没插入DOM,自然找不到menuBtn,调用addEventListener直接报错进入catch。
  2. 事件名语法错误:addEventListener(click, toggleHamBtn)里的click没加引号,属于未定义变量,这也是触发报错的直接原因。

解决步骤

1. 重构includeHTML为Promise兼容版本

修改include-html-code.js,让它能正确反馈异步加载的完成状态:

function includeHTML() {
  return new Promise((resolve, reject) => {
    var z, i, elmnt, file, xhttp;
    z = document.getElementsByTagName("*");
    let loadedCount = 0;
    let totalToLoad = 0;

    // 先统计需要加载的元素数量
    for (i = 0; i < z.length; i++) {
      if (z[i].getAttribute("INCLUDE-HTML")) {
        totalToLoad++;
      }
    }

    if (totalToLoad === 0) {
      resolve();
      return;
    }

    for (i = 0; i < z.length; i++) {
      elmnt = z[i];
      file = elmnt.getAttribute("INCLUDE-HTML");

      if (file) {
        xhttp = new XMLHttpRequest();
        xhttp.onreadystatechange = function () {
          if (this.readyState == 4) {
            if (this.status == 200) {
              elmnt.innerHTML = this.responseText;
            }
            if (this.status == 404) {
              elmnt.innerHTML = "Page not found.";
              reject(new Error(`Failed to load ${file}`));
            }
            elmnt.removeAttribute("INCLUDE-HTML");
            loadedCount++;
            // 所有元素加载完成后resolve
            if (loadedCount === totalToLoad) {
              resolve();
            }
          }
        };
        xhttp.open("GET", file, true);
        xhttp.send();
      }
    }
  });
}

2. 正确调用并绑定事件

修改index.html中的代码,等待includeHTML完成后再操作DOM,同时修正事件名的语法错误:

<head>    
    <script src="../Scripts/include-html-code.js" type="text/javascript"></script>
</head>
    
<body>
    <div INCLUDE-HTML="../html-block/artillery-nav.html"></div>

    <script type="text/javascript">
        // 用async/await等待加载完成
        async function initNav() {
            try {
                await includeHTML();
                console.log('导航栏加载完成');
                const togBtn = document.getElementById('menuBtn');
                // 注意click要加引号
                togBtn.addEventListener('click', toggleHamBtn);

                function toggleHamBtn() {
                    togBtn.classList.toggle('open');
                }
            } catch (err) {
                console.error('加载导航栏失败:', err);
            }
        }

        initNav();
    </script>
</body>
</html>

为什么之前的Promise写法无效?

你之前的Promise只是判断includeHTML()的返回值,但includeHTML不管异步请求完成没都会立刻返回true,等于完全没等待异步操作,自然拿不到刚加载的DOM元素。重构后的版本用Promise包裹整个异步加载流程,只有当所有HTML都插入DOM后才会resolve,此时再去获取元素就没问题了。

内容的提问来源于stack exchange,提问作者Artillery

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 18:47:11