开发者问题收集

无法从 javascript 中的 foreach 回调将 html 内容输出到页面

2020-02-03
69

我有一个函数,它循环遍历数组的每个元素并将 html 内容输出到页面,同时使用数组中的元素修改某些属性。我使用 forEach 循环遍历数组的元素,并使用 innerHTML 将内容打印到页面。

我不断收到以下错误: netdata.html:41 Uncaught TypeError: Cannot set property 'innerHTML' of null 。我不确定是什么原因造成的,因为我确实有一个具有正确 id 的元素, <div id="info"></div>

const clusterIPs = [
      { name: "eco-cluster-1", ip: "192.168.50.101" },
      { name: "eco-cluster-2", ip: "192.168.50.102" },
      { name: "eco-cluster-3", ip: "192.168.50.103" },
      { name: "eco-cluster-4", ip: "192.168.50.104" },
      { name: "eco-cluster-6", ip: "192.168.50.105" },
      { name: "eco-cluster-7", ip: "192.168.50.106" },
      { name: "eco-cluster-8", ip: "192.168.50.107" },
      { name: "eco-cluster-9", ip: "192.168.50.108" },
      { name: "eco-cluster-10", ip: "192.168.50.110" },
      { name: "eco-cluster-11", ip: "192.168.50.111" },
      { name: "eco-cluster-12", ip: "192.168.50.112" },
      { name: "eco-cluster-13", ip: "192.168.50.113" }
    ];

    clusterIPs.forEach(pc => {
      console.log(pc);

      //   $("body").html

      document.getElementById("info").innerHTML = `
        <div class="container-fluid">
        <div><h1>${pc.name}</h1></div>
        <div class="row">
        <div class="col-md">
          <div
            data-title="CPU"
            data-netdata="system.cpu"
            data-chart-library="dygraph"
            data-after="-600"
            data-host="http://${pc.ip}:19999/"
          ></div>
        </div>
        <div class="col-md">
          <div
            data-title="RAM"
            data-netdata="system.ram"
            data-chart-library="dygraph"
            data-after="-600"
            data-host="http://${pc.ip}:19999/"
          ></div>
        </div>
      </div>
      <div class="row">
        <div class="col-md">
          <div
            data-title="Disk I/O"
            data-netdata="system.io"
            data-chart-library="dygraph"
            data-after="-600"
            data-host="http://${pc.ip}:19999/"
          ></div>
        </div>
        <div class="col-md">
          <div
            data-title="Network Bandwidth"
            data-netdata="system.net"
            data-chart-library="dygraph"
            data-after="-600"
            data-host="http://${pc.ip}:19999/"
          ></div>
        </div>
      </div>
    </div>
        `;
    });
    //   console.log(clusterIPs)
2个回答

您正在

  1. 在容器存在之前添加 HTML。
  2. 每次在循环中替换 HTML,而不是附加

要使用 innerHTML,您可以执行

window.addEventListener("load",function() {
  const container = document.getElementById("info");
  clusterIPs.forEach(pc => container.innerHTML += `....`);
})

或者使用 jQuery 附加,因为您已经加载了它

$(function() { // on page load
  const $container = $("#info");
  $.each(clusterIPs,(i, pc) => {
    $container.append(`....`);
  });
});
const clusterIPs = [
      { name: "eco-cluster-1", ip: "192.168.50.101" },
      { name: "eco-cluster-2", ip: "192.168.50.102" },
      { name: "eco-cluster-3", ip: "192.168.50.103" },
      { name: "eco-cluster-4", ip: "192.168.50.104" },
      { name: "eco-cluster-6", ip: "192.168.50.105" },
      { name: "eco-cluster-7", ip: "192.168.50.106" },
      { name: "eco-cluster-8", ip: "192.168.50.107" },
      { name: "eco-cluster-9", ip: "192.168.50.108" },
      { name: "eco-cluster-10", ip: "192.168.50.110" },
      { name: "eco-cluster-11", ip: "192.168.50.111" },
      { name: "eco-cluster-12", ip: "192.168.50.112" },
      { name: "eco-cluster-13", ip: "192.168.50.113" }
    ];


$(function() { // on page load
  const $container = $("#info");
  $.each(clusterIPs,(i, pc) => {
    $container.append(`
        <div class="container-fluid">
        <div><h1>${pc.name}</h1></div>
        <div class="row">
        <div class="col-md">
          <div
            data-title="CPU"
            data-netdata="system.cpu"
            data-chart-library="dygraph"
            data-after="-600"
            data-host="http://${pc.ip}:19999/"
          ></div>
        </div>
        <div class="col-md">
          <div
            data-title="RAM"
            data-netdata="system.ram"
            data-chart-library="dygraph"
            data-after="-600"
            data-host="http://${pc.ip}:19999/"
          ></div>
        </div>
      </div>
      <div class="row">
        <div class="col-md">
          <div
            data-title="Disk I/O"
            data-netdata="system.io"
            data-chart-library="dygraph"
            data-after="-600"
            data-host="http://${pc.ip}:19999/"
          ></div>
        </div>
        <div class="col-md">
          <div
            data-title="Network Bandwidth"
            data-netdata="system.net"
            data-chart-library="dygraph"
            data-after="-600"
            data-host="http://${pc.ip}:19999/"
          ></div>
        </div>
      </div>
    </div>`)
  });
});
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous" />

<div id="info"></div>

<script type="text/javascript" src="http://localhost:19999/dashboard.js"></script>
<script src="https://code.jquery.com/jquery-3.4.1.slim.min.js" integrity="sha256-pasqAKBDmFT4eHoN2ndd6lN370kFiGUFyTiUHWhU7k8=" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js" integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6" crossorigin="anonymous"></script>
mplungjan
2020-02-03

脚本运行时, div#info 元素不可用。有几种方法可以解决此问题:

  1. DOMContentLoaded 事件侦听器添加到 document 对象,然后在回调中运行现有脚本。
  2. div#info 元素之后添加包含现有脚本的 <script> 标记。
  3. 重构您编写的脚本。我个人会这样写:

代表 HTML 元素的组件

class Component {
  constructor() {}
  get element() {
    if(this._element) return this._element
    this._element = document.createElement('div')
    this._element.setAttribute('id', 'info')
    return this._element
  }
  get data() { return [
    { name: "eco-cluster-1", ip: "192.168.50.101" },
    { name: "eco-cluster-2", ip: "192.168.50.102" },
    { name: "eco-cluster-3", ip: "192.168.50.103" },
    { name: "eco-cluster-4", ip: "192.168.50.104" },
    { name: "eco-cluster-6", ip: "192.168.50.105" },
    { name: "eco-cluster-7", ip: "192.168.50.106" },
    { name: "eco-cluster-8", ip: "192.168.50.107" },
    { name: "eco-cluster-9", ip: "192.168.50.108" },
    { name: "eco-cluster-10", ip: "192.168.50.110" },
    { name: "eco-cluster-11", ip: "192.168.50.111" },
    { name: "eco-cluster-12", ip: "192.168.50.112" },
    { name: "eco-cluster-13", ip: "192.168.50.113" }
  ] }
  get template() { return (pc) => `
    <div class="container-fluid">
      <div><h1>${pc.name}</h1></div>
      <div class="row">
        <div class="col-md">
          <div
            data-title="CPU"
            data-netdata="system.cpu"
            data-chart-library="dygraph"
            data-after="-600"
            data-host="http://${pc.ip}:19999/"
          ></div>
        </div>
        <div class="col-md">
          <div
            data-title="RAM"
            data-netdata="system.ram"
            data-chart-library="dygraph"
            data-after="-600"
            data-host="http://${pc.ip}:19999/"
          ></div>
        </div>
      </div>
      <div class="row">
        <div class="col-md">
          <div
            data-title="Disk I/O"
            data-netdata="system.io"
            data-chart-library="dygraph"
            data-after="-600"
            data-host="http://${pc.ip}:19999/"
          ></div>
        </div>
        <div class="col-md">
          <div
            data-title="Network Bandwidth"
            data-netdata="system.net"
            data-chart-library="dygraph"
            data-after="-600"
            data-host="http://${pc.ip}:19999/"
          ></div>
        </div>
      </div>
    </div>
  ` }
  insertElement() {
    document.querySelector('body')
      .insertAdjacentElement('afterbegin', this.element)
    return this
  }
  clearElement() {
    this.element.innerHTML = ''
    return this
  }
  render() {
    if(!this.element.parentElement) {
      this.insertElement()
    } else {
      this.clearElement()
    }
    this.data.forEach((dataItem) => {
      let template = document.createRange().createContextualFragment(
        this.template(dataItem)
      )
      this.element.appendChild(template)
    })
    return this
  }
}

实例化组件

document.addEventListener('DOMContentLoaded', (event) => {
  let component = new Component()
  component.render()
})

Miaplacidus
2020-02-03