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

onclick事件无法获取className元素追加内容 报length读取错误

报错根因

控制台抛出Cannot read properties of null (reading 'length')是三处代码逻辑错误导致的:

  1. 你在页面刚加载完成、还没有任何按钮被选中时,就执行了let results = document.querySelector('.btn.button-focus'),此时没有匹配元素,querySelector会返回null,后续提交事件中读取results.length就会触发空引用错误。另外querySelector只会返回第一个匹配的DOM元素,本身也没有length属性,就算初始有选中按钮也不符合获取所有选中项的需求。
  2. 判断按钮是否带button-focus类的逻辑存在缺陷:遍历classList时,只要最后一个遍历到的类名不是button-focus,就会把isPresent重置为false,哪怕之前已经遍历到目标类名也会被覆盖,导致选中状态判断错误。
  3. 提交逻辑的遍历写法有误:就算拿到了元素集合,循环里push的是整个集合对象,不是单个选中按钮的值,达不到收集选中内容的目的。
修复方案

按以下点修改代码即可:

  • 将获取选中按钮的逻辑移到提交按钮的点击事件内部,每次点击提交时再实时查询当前带button-focus类的按钮,保证拿到最新的选中状态
  • 用querySelectorAll('.btn.button-focus')替换querySelector,该方法会返回所有匹配元素的NodeList集合,支持长度读取和遍历
  • 替换手写的classList遍历判断逻辑,直接用原生APIelement.classList.contains('button-focus')判断类是否存在,避免逻辑漏洞
  • 遍历选中元素集合时,逐个读取元素的value属性存入结果数组,不要直接传入整个集合对象
修复后可运行代码
<!DOCTYPE html>
<html>
<head>
<style>
:root {
--primary_orange: #fea501;
--dark: #000;
--primary_med: #f5f5f5;
--shadow: 0 2px 4px rgba(0,0,0,0.2);
}
.my_dataviz {
    width: auto;
    height: auto;
    margin-top: 15px;
    margin-bottom: 15px;
    display: flex;
    flex-wrap: wrap;
    align-content: center;
    justify-content: space-evenly;
}
.my_dataviz button {
    font-family: "walkway", sans-serif;
    font-size: 16px;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: center;
    width: 130px;
    height: 25px;
    background-color: Transparent;
    -webkit-tap-highlight-color: transparent;
    background-repeat:no-repeat;
    border: none;
    letter-spacing: 1.6px;
    margin: 10px;
    border: 1px solid transparent;
}
.my_dataviz button:hover {
    box-sizing: border-box;
    background-color: var(--primary_orange);
    color: var(--dark);
    font-weight: bold;
    border: 1px solid #000;
    border-radius: 5px;
    cursor: pointer;
}
.btn.button-focus {
    background-color: var(--primary_orange);
    color: var(--dark);
    font-weight: bold;
    border: 1px solid #000;
    border-radius: 5px;
}
.modal-footer {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    height: 50px;
    align-items: center;
    text-align: center;
    background: var(--primary_med);
    border-bottom-left-radius: 10px;
    border-bottom-right-radius: 10px;
}
.modal-footer .modal-btn {
    font-family: "walkway", sans-serif;
    font-size: 16px;
    font-weight: bold;
    width: 100px;
    height: 28px;
    border-radius: 5px;
    align-items: center;
    letter-spacing: 1.6px;
    box-shadow: var(--shadow);
    cursor: pointer;
}
</style>
</head>
<body>
<div class="my_dataviz" id="my_dataviz">

</div>
<div class="modal-footer">
  <input class="modal-btn" type="button" value="Select it" />
</div>

<script>
var container = document.getElementById('my_dataviz');
var array = ["One", "Two", "Three", "Four", "Five", "Six",
  "Seven", "Eight", "Nine", "Ten"
]
let SelectCount = 0;

array.forEach(element => {
  const button = document.createElement("button");
  button.className = "btn";
  button.id = element;
  button.value = element;
  button.type = "button";
  const text = document.createTextNode(element);
  button.appendChild(text);
  container.appendChild(button);
});

let btn = document.getElementsByClassName("btn");

for (let i = 0; i < btn.length; i++) {
  btn[i].addEventListener("click", function() {
    console.log("Clicked Button: " + i);
    // 直接用原生API判断类是否存在,修复原遍历判断的逻辑bug
    const isPresent = this.classList.contains("button-focus");

    if (isPresent) {
      this.classList.remove("button-focus");
      SelectCount -= 1;
      // 取消选中后恢复所有按钮可用
      document.querySelectorAll('.btn').forEach(item => {
        item.disabled = false
      })
    } else {
      this.classList.add("button-focus");
      SelectCount += 1;
      if (SelectCount > 2) {
        // 选中超过2个时禁用未选中按钮
        document.querySelectorAll('.btn').forEach(item => {
          if (!item.classList.contains('button-focus')) item.disabled = true
        })
      }
    }
  })
}

const dataResults = []
let submit_button = document.querySelector('.modal-btn');

submit_button.onclick = function() {
  // 每次点击提交时实时获取最新的选中按钮,用querySelectorAll获取集合
  const selectedBtns = document.querySelectorAll('.btn.button-focus');
  // 清空上次提交的结果,避免重复累加
  dataResults.length = 0;
  for (let i = 0; i < selectedBtns.length; ++i) {
    // 存入按钮的value值,不是DOM对象本身
    dataResults.push(selectedBtns[i].value)
  }
  console.log("收集到的选中值:", dataResults)
}
</script>
</body>
</html>

修复后最多可选3个选项,点击提交后控制台会打印当前选中的所有值,不会再抛出空引用错误。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 23:16:31