回到基础:如何用原生 DOM API 生成表格

翻译:疯狂的技术宅
原文: https://www.valentinog.com/bl...

本文首发微信公众号:jingchengyideng
欢迎关注,天天都给你推送新鲜的前端技术文章javascript


怎样用原生 JavaScript 生成表格需?本文告诉你答案!html

clipboard.png

这是一个刷 JavaScript 经验值的好机会:在技术面试中出现的最多的一个问题就是怎样用原生 API 操做 DOM 前端

在下面的教程中,咱们将了解如何使用 JavaScript 生成表格,而无需依赖任何库或框架。java

你将学到些什么

在本教程中,你将学习如何:git

  • 用 JavaScript 生成一个表格
  • 用本机 DOM API 来操做表

要求

要学习本教程,你应该对 HTML 和 JavaScript 有基本的了解。程序员

需求

Eloquent JavaScript 是一本很是好的 JavaScript 书籍。这本书很简洁,也不乏味,同时有大量的练习。如下练习改编自第 14 章,它被称为“构建表格”。github

题目要求你用 JavaScript 构建一个 HTML 表。你的任务是依据 “mountains” 数组中的数据生成表格,将对象中的key对应到列而且每行一个对象面试

每一个对象都是以下形式:json

{ name: "Monte Falco", height: 1658, place: "Parco Foreste Casentinesi" }

咱们有一个名称,一个高度和一个山峰所在的位置。但 HTML 表格是什么? HTML 表格是包含表格数据的元素,以行和列的形式显示。这意味着给出如下数组:bootstrap

let mountains = [
  { name: "Monte Falco", height: 1658, place: "Parco Foreste Casentinesi" },
  { name: "Monte Falterona", height: 1654, place: "Parco Foreste Casentinesi" }
];

咱们打算生成下表:

<table>
    <thead>
    <tr>
        <th>name</th>
        <th>height</th>
        <th>place</th>
    </tr>
    </thead>
    <tbody>
    <tr>
        <td>Monte Falco</td>
        <td>1658</td>
        <td>Parco Foreste Casentinesi</td>
    </tr>
    <tr>
        <td>Monte Falterona</td>
        <td>1654</td>
        <td>Parco Foreste Casentinesi</td>
    </tr>
    </tbody>
</table>

如你所见,该表有一个 thead(表头),其中包含一个具备三个th(表格标题)tr(表格行)

而后是tbody(表体) 中包含一堆 tr(表格行)。每一个表格行包含必定数量的 td元素(表格单元格)

有了这些要求,就能够开始编写 JavaScript 文件了。咱们的起点能够是如下 HTML:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Build a table</title>
</head>
<body>
<table>
<!-- here goes our data! -->
</table>
</body>
<script src="build-table.js"></script>
</html>

将文件另存为 build-table.html 并继续下一部分。

生成表头

在与 build-table.html 相同的文件夹中建立一个名为 build-table.js 的新文件,并在文件定义数组:

let mountains = [
  { name: "Monte Falco", height: 1658, place: "Parco Foreste Casentinesi" },
  { name: "Monte Falterona", height: 1654, place: "Parco Foreste Casentinesi" },
  { name: "Poggio Scali", height: 1520, place: "Parco Foreste Casentinesi" },
  { name: "Pratomagno", height: 1592, place: "Parco Foreste Casentinesi" },
  { name: "Monte Amiata", height: 1738, place: "Siena" }
];

第一个目标是生成表头。咱们知道本机方法 createElement() 会建立传递给它的任何元素。假设咱们要建立一个表头,能够用 document.createElement(‘thead’)。不过还有更好的办法吗?

让咱们先到 MDN 上查阅一下 element table reference 。你能够看到表格的DOM接口是 HTMLTableElement

HTMLTableElement 的有趣之处在于它公开的方法中有 createTHead()。没错!createTHead 返回与给定表关联的表头元素,更 6 的是,若是表中不存在头的话,createTHead 会帮咱们建立一个。

有了这些知识,接下来在咱们的文件中建立一个函数,将 table 做为参数。鉴于咱们的需求,能够在其中建立一个新的 thead

function generateTableHead(table) {
  let thead = table.createTHead();
}

如今找到咱们的表格(记住在 build-table.html 中有一个)并将其传给咱们的函数:

function generateTableHead(table) {
  let thead = table.createTHead();
}

let table = document.querySelector("table");
generateTableHead(table);

若是你在浏览器中打开 build-table.html,在屏幕上还看不到任何内容,不过能够在开发者工具中看处处理的结果。填充表头的工做只作了一半,能够看到表头中填充了一堆 th。每一个表头必须映射到对象描述数据组成的 key 上。

信息已经存在于数组 mountains 中的第一个对象内部。能够迭代第一个对象的 key:

let mountains = [
  { name: "Monte Falco", height: 1658, place: "Parco Foreste Casentinesi" },
    //
];

而后用获得的 key 生成三个表头。可是要先在 thead 中添加一行!这时候该用 document.createElement(“TR”) 了吧?不不不。HTMLTableRowElement 提供了一个 insertRow() 方法,能够在表头上调用。让咱们重构一下 generateTableHead 函数:

function generateTableHead(table) {
  let thead = table.createTHead();
  let row = thead.insertRow();
}

新行应包含三个 th(表头),须要手动建立,对于每一个 th 元素,咱们将附加一个文本节点。这个函数可使用另外一个参数来进行迭代:

function generateTableHead(table, data) {
  let thead = table.createTHead();
  let row = thead.insertRow();
  for (let key of data) {
    let th = document.createElement("th");
    let text = document.createTextNode(key);
    th.appendChild(text);
    row.appendChild(th);
  }
}

let table = document.querySelector("table");
let data = Object.keys(mountains[0]);
generateTableHead(table, data);

保存文件并刷新 build-table.html:你应该看到你的表头中被填充了 name、height 和 place。 有时用 React 和 Vue 偷懒的感受真好,直接操做 DOM 是多么艰难和繁琐。不过咱们的工做尚未完成。

接下来该填表了......

生成行和单元格

为了填充表格能够遵循一样的方法,但此次咱们须要迭代 mountains 数组中的每一个对象。当进入 for…of 循环时,将为每一个项目建立一个新行

要建立行,你将用到 insertRow()

但咱们不能止步于此。在主循环内部,须要一个内循环,此次要用到 for... in 。内部循环迭代当前对象的每一个 key,同时它:

  • 建立一个新单元格
  • 建立一个新的文本节点
  • 将文本节点附加到单元格

使用 HTMLTableRowElement 的另外一个方法 insertCell() 建立单元格。

也就是说经过以上逻辑能够填充咱们的表。打开 build-table.js 并建立一个名为 generateTable 的新函数。命名能够与咱们现有的函数相同:

function generateTable(table, data) {
  for (let element of data) {
    let row = table.insertRow();
    for (key in element) {
      let cell = row.insertCell();
      let text = document.createTextNode(element[key]);
      cell.appendChild(text);
    }
  }
}

能够这样调用它:

generateTable(table, mountains);

最后来看看完整的代码:

let mountains = [
  { name: "Monte Falco", height: 1658, place: "Parco Foreste Casentinesi" },
  { name: "Monte Falterona", height: 1654, place: "Parco Foreste Casentinesi" },
  { name: "Poggio Scali", height: 1520, place: "Parco Foreste Casentinesi" },
  { name: "Pratomagno", height: 1592, place: "Parco Foreste Casentinesi" },
  { name: "Monte Amiata", height: 1738, place: "Siena" }
];

function generateTableHead(table, data) {
  let thead = table.createTHead();
  let row = thead.insertRow();
  for (let key of data) {
    let th = document.createElement("th");
    let text = document.createTextNode(key);
    th.appendChild(text);
    row.appendChild(th);
  }
}

function generateTable(table, data) {
  for (let element of data) {
    let row = table.insertRow();
    for (key in element) {
      let cell = row.insertCell();
      let text = document.createTextNode(element[key]);
      cell.appendChild(text);
    }
  }
}

let table = document.querySelector("table");
let data = Object.keys(mountains[0]);
generateTableHead(table, data);
generateTable(table, mountains);

你以为它能工做吗?让咱们来试试看:

clipboard.png

呃……看起来行被附加到了表头而不是表体。另外没有table body

可是若是切换函数调用顺序会怎么样呢?试试吧:

// omitted for brevity

let table = document.querySelector("table");
let data = Object.keys(mountains[0]);
generateTable(table, mountains); // generate the table first
generateTableHead(table, data); // then the head

再次刷新浏览器:

clipboard.png

好使!另外还获得了一个 tbody。为何会这样?当你在空表上调用 insertRow() 时,这些方法会为自动你建立一个tbody(若是没有的话)。

作得好!不过咱们的代码可能没进行很好的组织(有太多的全局绑定),这些将会在下一篇文章中提到。

到此为止,你应该可以在不依赖任何外部库的状况下操做HTML表了。恭喜!

总结

在本教程中,咱们学到了如何用原生 JavaScript 生成表格。 HTML 表格在DOM中由 HTMLTableElement 体现。这个接口公开了不少有用的方法,其中 createTHead 用于操做表头,insertRow 用来插入行。

另外 HTML 表格的行继承自 HTMLTableRowElement。这个接口有两种方法,其中最重要的是 insertCell

给定一个对象数组,可使用 for…of 循环来迭代生成行。对于每一个对象,咱们可使用 for … in 生成单元格。

咱们有一些带有全局绑定的代码(请参阅执行上下文和调用堆栈以获取更多信息)。在下一篇文章中,咱们将看到怎样重构这些代码。

jQuery正逐渐消失。 Bootstrap将在版本5中删除它原生DOM API 愈来愈好了,替换之前用 jQuery 作的事情是可行的,没有(几乎)任何额外的依赖。

但即便没有 jQuery 也很容易掉进坑里。有人说你不该该在没有 $shinyNewLibrary 的状况下去操纵 DOM。实际上每一个认真的 JavaScript 开发人员都应该知道原生 DOM API,以及如何使用 JavaScript 操做 DOM 。这些问题在技术面试中很容易被问到,你不想所以被拒绝吧?

本教程的代码可在 Github 下载(https://github.com/valentinog...)。

感谢阅读并敬请期待后续!


欢迎继续阅读本专栏其它高赞文章:


本文首发微信公众号:jingchengyideng

欢迎扫描二维码关注公众号,天天都给你推送新鲜的前端技术文章

欢迎扫描二维码关注公众号,天天都给你推送新鲜的前端技术文章

相关文章
相关标签/搜索