JS 自定义 table 元素总是缺少 1 行
JS custom table element missing always 1 row
我制作了一个自定义 TABLE 元素,它通过 'rows' 属性更新了行数,但它少了一行,
例如:我设置 rows='10' 输出行数为 9。
我知道,如果我删除添加到 'TBODY' 的 div 元素,问题就解决了,但我希望它在 'TBODY' 中,但我不明白为什么会这样正因为如此 div.
注意:全屏运行需要
'use strict';
class betterTable extends HTMLElement {
#colsLength;
constructor() {
super();
this.#colsLength = 0;
/* TABLE */
this.table = document.createElement('table');
/* HEADER */
this.thead = document.createElement('thead');
this.table.appendChild(this.thead);
this.theadRow = document.createElement('tr');
this.thead.appendChild(this.theadRow);
/* BODY */
this.tbody = document.createElement('tbody');
this.table.appendChild(this.tbody);
this.scrollbar = document.createElement('div');
this.tbody.appendChild(this.scrollbar);
}
connectedCallback() {
this.render();
}
render() {
this.appendChild(this.table);
}
setColumn(colsName = ['null']) {
this.setCell(this.theadRow, colsName.length, colsName);
this.#colsLength = colsName.length;
this.cols = colsName.length;
}
setCell(row, len = this.#colsLength, cellText = new Array(this.#colsLength)) {
// Remove unnecessary cells
while (row.childNodes.length > len) row.lastChild.remove();
// Add missing cells
for (let i = 0; len > row.childNodes.length; i++) {
const cell = row.parentNode
? row.parentNode.tagName === 'THEAD'
? document.createElement('th')
: document.createElement('td')
: document.createElement('td');
row.appendChild(cell);
}
for (let i = 0; i < row.childNodes.length; i++) {
if (typeof cellText[i] === 'string') {
if (row.childNodes[i].innerText != cellText[i]) {
row.childNodes[i].innerText = cellText[i];
}
} else if (cellText[i] instanceof Element) {
row.childNodes[i].appendChild = cellText[i];
} else {
if (row.childNodes[i].innerText != 'null') {
row.childNodes[i].innerText = 'null';
}
}
}
}
addRow(body, dataCell) {
const row = document.createElement('tr');
this.setCell(row, this.#colsLength, dataCell);
body.appendChild(row);
}
addMultiRow(body, dataCell = ['null']) {
// Remove unnecessary rows
for (let i = body.childNodes.length - 1; body.childNodes.length - 1 > dataCell.length; i--) {
let row = body.childNodes[i];
if (row && row.tagName === 'TR') {
row.remove();
}
}
for (let i = 0; i < dataCell.length; i++) {
let row = body.childNodes[i];
if (row && row.tagName === 'TR') {
this.setCell(row, this.#colsLength, dataCell[i]);
} else {
// Add missing rows
this.addRow(body, dataCell[i]);
}
}
}
/* ///////////// Attributes ///////////// */
static get observedAttributes() {
return ['cols', 'rows'];
}
attributeChangedCallback(name, oldValue, newValue) {
let len;
switch (name) {
case 'cols':
len = parseInt(newValue);
if (len !== NaN && this.#colsLength !== len && newValue != oldValue) {
this.setColumn(new Array(len));
}
break;
case 'rows':
len = parseInt(newValue);
if (len !== NaN && newValue != oldValue) {
const rows = new Array(len).fill(new Array(len).fill('1'));
this.addMultiRow(this.tbody, rows);
}
break;
default:
break;
}
}
/* // GETTER & SETTER // */
get length() {
return this.#colsLength;
}
get cols() {
return this.getAttribute('cols');
}
get rows() {
return this.getAttribute('rows');
}
set cols(num) {
this.setAttribute('cols', num);
}
set rows(num) {
this.setAttribute('rows', num);
}
}
customElements.define('better-table', betterTable);
* {
margin: 0;
padding: 0;
}
/* //////////////////////////////////////// */
/* //////////// Global Style ////////////// */
/* //////////////////////////////////////// */
/* /// The Table Itself /// */
better-table {
width: 100%;
height: 100%;
}
table {
width: 100%;
height: 100%;
display: table;
box-sizing: border-box;
}
table thead,
table tbody,
table tr {
width: 100%;
display: table;
table-layout: fixed;
}
table tbody tr {
border-bottom: 1px solid black;
}
table th,
table td {
padding: 12px 15px;
overflow-x: hidden;
}
/* //////////////////////////////////////// */
/* //////////////////////////////////////// */
/* ///////// Header/Column Style ////////// */
/* //////////////////////////////////////// */
/* /// Header/Column row style /// */
table thead {
background: #f38181;
}
table thead tr {
position: sticky;
top: 0;
text-align: center;
}
/* //////////////////////////////////////// */
/* //////////////////////////////////////// */
/* /////// Body/Row Contents Style //////// */
/* //////////////////////////////////////// */
table tbody {
display: block;
overflow: hidden;
table-layout: fixed;
max-height: 65vh;
}
/* /// even row /// */
table tbody tr {
text-align: center;
background-color: #fddfdf;
color: #000;
}
/* /// odd row /// */
table tbody tr:nth-child(even) {
background-color: #eba4a4;
color: #000;
}
/* //////////////////////////////////////// */
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<link rel="stylesheet" href="table.css" />
<script defer type="module" src="./table.js"></script>
</head>
<body>
<style>
html,
body {
width: 100%;
height: 100%;
overflow: hidden;
}
.content {
width: 100%;
height: 500px;
}
.box {
position: absolute;
left: 20px;
bottom: 50px;
}
</style>
<div class="content">
<better-table cols="4" rows="10" lang="heb"></better-table>
</div>
</body>
</html>
此逻辑导致您的行附加问题
for (let i = 0; i < dataCell.length; i++) {
let row = body.childNodes[i];
if (row && row.tagName === 'TR') {
//after the first row added
//it goes inside this, so it never call `addRow` (one row is missing from here)
this.setCell(row, this.#colsLength, dataCell[i]);
} else {
// the first row added
this.addRow(body, dataCell[i]);
}
}
可能的解决方法是
for (let i = 0; i < dataCell.length; i++) {
this.addRow(body, dataCell[i]);
}
根据您的逻辑,我假设您最初没有行,因此我们不需要检查 tbody
中的现有行
'use strict';
class betterTable extends HTMLElement {
#colsLength;
constructor() {
super();
this.#colsLength = 0;
/* TABLE */
this.table = document.createElement('table');
/* HEADER */
this.thead = document.createElement('thead');
this.table.appendChild(this.thead);
this.theadRow = document.createElement('tr');
this.thead.appendChild(this.theadRow);
/* BODY */
this.tbody = document.createElement('tbody');
this.table.appendChild(this.tbody);
this.scrollbar = document.createElement('div');
this.tbody.appendChild(this.scrollbar);
}
connectedCallback() {
this.render();
}
render() {
this.appendChild(this.table);
}
setColumn(colsName = ['null']) {
this.setCell(this.theadRow, colsName.length, colsName);
this.#colsLength = colsName.length;
this.cols = colsName.length;
}
setCell(row, len = this.#colsLength, cellText = new Array(this.#colsLength)) {
// Remove unnecessary cells
while (row.childNodes.length > len) row.lastChild.remove();
// Add missing cells
for (let i = 0; len > row.childNodes.length; i++) {
const cell = row.parentNode
? row.parentNode.tagName === 'THEAD'
? document.createElement('th')
: document.createElement('td')
: document.createElement('td');
row.appendChild(cell);
}
for (let i = 0; i < row.childNodes.length; i++) {
if (typeof cellText[i] === 'string') {
if (row.childNodes[i].innerText != cellText[i]) {
row.childNodes[i].innerText = cellText[i];
}
} else if (cellText[i] instanceof Element) {
row.childNodes[i].appendChild = cellText[i];
} else {
if (row.childNodes[i].innerText != 'null') {
row.childNodes[i].innerText = 'null';
}
}
}
}
addRow(body, dataCell) {
const row = document.createElement('tr');
this.setCell(row, this.#colsLength, dataCell);
body.appendChild(row);
}
addMultiRow(body, dataCell = ['null']) {
// Remove unnecessary rows
for (let i = body.childNodes.length - 1; body.childNodes.length - 1 > dataCell.length; i--) {
let row = body.childNodes[i];
if (row && row.tagName === 'TR') {
row.remove();
}
}
//adding rows
for (let i = 0; i < dataCell.length; i++) {
this.addRow(body, dataCell[i]);
}
}
/* ///////////// Attributes ///////////// */
static get observedAttributes() {
return ['cols', 'rows'];
}
attributeChangedCallback(name, oldValue, newValue) {
let len;
switch (name) {
case 'cols':
len = parseInt(newValue);
if (len !== NaN && this.#colsLength !== len && newValue != oldValue) {
this.setColumn(new Array(len));
}
break;
case 'rows':
len = parseInt(newValue);
if (len !== NaN && newValue != oldValue) {
const rows = new Array(len).fill(new Array(len).fill('1'));
this.addMultiRow(this.tbody, rows);
}
break;
default:
break;
}
}
/* // GETTER & SETTER // */
get length() {
return this.#colsLength;
}
get cols() {
return this.getAttribute('cols');
}
get rows() {
return this.getAttribute('rows');
}
set cols(num) {
this.setAttribute('cols', num);
}
set rows(num) {
this.setAttribute('rows', num);
}
}
customElements.define('better-table', betterTable);
* {
margin: 0;
padding: 0;
}
/* //////////////////////////////////////// */
/* //////////// Global Style ////////////// */
/* //////////////////////////////////////// */
/* /// The Table Itself /// */
better-table {
width: 100%;
height: 100%;
}
table {
width: 100%;
height: 100%;
display: table;
box-sizing: border-box;
}
table thead,
table tbody,
table tr {
width: 100%;
display: table;
table-layout: fixed;
}
table tbody tr {
border-bottom: 1px solid black;
}
table th,
table td {
padding: 12px 15px;
overflow-x: hidden;
}
/* //////////////////////////////////////// */
/* //////////////////////////////////////// */
/* ///////// Header/Column Style ////////// */
/* //////////////////////////////////////// */
/* /// Header/Column row style /// */
table thead {
background: #f38181;
}
table thead tr {
position: sticky;
top: 0;
text-align: center;
}
/* //////////////////////////////////////// */
/* //////////////////////////////////////// */
/* /////// Body/Row Contents Style //////// */
/* //////////////////////////////////////// */
table tbody {
display: block;
overflow: hidden;
table-layout: fixed;
max-height: 65vh;
}
/* /// even row /// */
table tbody tr {
text-align: center;
background-color: #fddfdf;
color: #000;
}
/* /// odd row /// */
table tbody tr:nth-child(even) {
background-color: #eba4a4;
color: #000;
}
/* //////////////////////////////////////// */
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<link rel="stylesheet" href="table.css" />
<script defer type="module" src="./table.js"></script>
</head>
<body>
<style>
html,
body {
width: 100%;
height: 100%;
overflow: hidden;
}
.content {
width: 100%;
height: 500px;
}
.box {
position: absolute;
left: 20px;
bottom: 50px;
}
</style>
<div class="content">
<better-table cols="4" rows="10" lang="heb"></better-table>
</div>
</body>
</html>
我制作了一个自定义 TABLE 元素,它通过 'rows' 属性更新了行数,但它少了一行,
例如:我设置 rows='10' 输出行数为 9。
我知道,如果我删除添加到 'TBODY' 的 div 元素,问题就解决了,但我希望它在 'TBODY' 中,但我不明白为什么会这样正因为如此 div.
注意:全屏运行需要
'use strict';
class betterTable extends HTMLElement {
#colsLength;
constructor() {
super();
this.#colsLength = 0;
/* TABLE */
this.table = document.createElement('table');
/* HEADER */
this.thead = document.createElement('thead');
this.table.appendChild(this.thead);
this.theadRow = document.createElement('tr');
this.thead.appendChild(this.theadRow);
/* BODY */
this.tbody = document.createElement('tbody');
this.table.appendChild(this.tbody);
this.scrollbar = document.createElement('div');
this.tbody.appendChild(this.scrollbar);
}
connectedCallback() {
this.render();
}
render() {
this.appendChild(this.table);
}
setColumn(colsName = ['null']) {
this.setCell(this.theadRow, colsName.length, colsName);
this.#colsLength = colsName.length;
this.cols = colsName.length;
}
setCell(row, len = this.#colsLength, cellText = new Array(this.#colsLength)) {
// Remove unnecessary cells
while (row.childNodes.length > len) row.lastChild.remove();
// Add missing cells
for (let i = 0; len > row.childNodes.length; i++) {
const cell = row.parentNode
? row.parentNode.tagName === 'THEAD'
? document.createElement('th')
: document.createElement('td')
: document.createElement('td');
row.appendChild(cell);
}
for (let i = 0; i < row.childNodes.length; i++) {
if (typeof cellText[i] === 'string') {
if (row.childNodes[i].innerText != cellText[i]) {
row.childNodes[i].innerText = cellText[i];
}
} else if (cellText[i] instanceof Element) {
row.childNodes[i].appendChild = cellText[i];
} else {
if (row.childNodes[i].innerText != 'null') {
row.childNodes[i].innerText = 'null';
}
}
}
}
addRow(body, dataCell) {
const row = document.createElement('tr');
this.setCell(row, this.#colsLength, dataCell);
body.appendChild(row);
}
addMultiRow(body, dataCell = ['null']) {
// Remove unnecessary rows
for (let i = body.childNodes.length - 1; body.childNodes.length - 1 > dataCell.length; i--) {
let row = body.childNodes[i];
if (row && row.tagName === 'TR') {
row.remove();
}
}
for (let i = 0; i < dataCell.length; i++) {
let row = body.childNodes[i];
if (row && row.tagName === 'TR') {
this.setCell(row, this.#colsLength, dataCell[i]);
} else {
// Add missing rows
this.addRow(body, dataCell[i]);
}
}
}
/* ///////////// Attributes ///////////// */
static get observedAttributes() {
return ['cols', 'rows'];
}
attributeChangedCallback(name, oldValue, newValue) {
let len;
switch (name) {
case 'cols':
len = parseInt(newValue);
if (len !== NaN && this.#colsLength !== len && newValue != oldValue) {
this.setColumn(new Array(len));
}
break;
case 'rows':
len = parseInt(newValue);
if (len !== NaN && newValue != oldValue) {
const rows = new Array(len).fill(new Array(len).fill('1'));
this.addMultiRow(this.tbody, rows);
}
break;
default:
break;
}
}
/* // GETTER & SETTER // */
get length() {
return this.#colsLength;
}
get cols() {
return this.getAttribute('cols');
}
get rows() {
return this.getAttribute('rows');
}
set cols(num) {
this.setAttribute('cols', num);
}
set rows(num) {
this.setAttribute('rows', num);
}
}
customElements.define('better-table', betterTable);
* {
margin: 0;
padding: 0;
}
/* //////////////////////////////////////// */
/* //////////// Global Style ////////////// */
/* //////////////////////////////////////// */
/* /// The Table Itself /// */
better-table {
width: 100%;
height: 100%;
}
table {
width: 100%;
height: 100%;
display: table;
box-sizing: border-box;
}
table thead,
table tbody,
table tr {
width: 100%;
display: table;
table-layout: fixed;
}
table tbody tr {
border-bottom: 1px solid black;
}
table th,
table td {
padding: 12px 15px;
overflow-x: hidden;
}
/* //////////////////////////////////////// */
/* //////////////////////////////////////// */
/* ///////// Header/Column Style ////////// */
/* //////////////////////////////////////// */
/* /// Header/Column row style /// */
table thead {
background: #f38181;
}
table thead tr {
position: sticky;
top: 0;
text-align: center;
}
/* //////////////////////////////////////// */
/* //////////////////////////////////////// */
/* /////// Body/Row Contents Style //////// */
/* //////////////////////////////////////// */
table tbody {
display: block;
overflow: hidden;
table-layout: fixed;
max-height: 65vh;
}
/* /// even row /// */
table tbody tr {
text-align: center;
background-color: #fddfdf;
color: #000;
}
/* /// odd row /// */
table tbody tr:nth-child(even) {
background-color: #eba4a4;
color: #000;
}
/* //////////////////////////////////////// */
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<link rel="stylesheet" href="table.css" />
<script defer type="module" src="./table.js"></script>
</head>
<body>
<style>
html,
body {
width: 100%;
height: 100%;
overflow: hidden;
}
.content {
width: 100%;
height: 500px;
}
.box {
position: absolute;
left: 20px;
bottom: 50px;
}
</style>
<div class="content">
<better-table cols="4" rows="10" lang="heb"></better-table>
</div>
</body>
</html>
此逻辑导致您的行附加问题
for (let i = 0; i < dataCell.length; i++) {
let row = body.childNodes[i];
if (row && row.tagName === 'TR') {
//after the first row added
//it goes inside this, so it never call `addRow` (one row is missing from here)
this.setCell(row, this.#colsLength, dataCell[i]);
} else {
// the first row added
this.addRow(body, dataCell[i]);
}
}
可能的解决方法是
for (let i = 0; i < dataCell.length; i++) {
this.addRow(body, dataCell[i]);
}
根据您的逻辑,我假设您最初没有行,因此我们不需要检查 tbody
'use strict';
class betterTable extends HTMLElement {
#colsLength;
constructor() {
super();
this.#colsLength = 0;
/* TABLE */
this.table = document.createElement('table');
/* HEADER */
this.thead = document.createElement('thead');
this.table.appendChild(this.thead);
this.theadRow = document.createElement('tr');
this.thead.appendChild(this.theadRow);
/* BODY */
this.tbody = document.createElement('tbody');
this.table.appendChild(this.tbody);
this.scrollbar = document.createElement('div');
this.tbody.appendChild(this.scrollbar);
}
connectedCallback() {
this.render();
}
render() {
this.appendChild(this.table);
}
setColumn(colsName = ['null']) {
this.setCell(this.theadRow, colsName.length, colsName);
this.#colsLength = colsName.length;
this.cols = colsName.length;
}
setCell(row, len = this.#colsLength, cellText = new Array(this.#colsLength)) {
// Remove unnecessary cells
while (row.childNodes.length > len) row.lastChild.remove();
// Add missing cells
for (let i = 0; len > row.childNodes.length; i++) {
const cell = row.parentNode
? row.parentNode.tagName === 'THEAD'
? document.createElement('th')
: document.createElement('td')
: document.createElement('td');
row.appendChild(cell);
}
for (let i = 0; i < row.childNodes.length; i++) {
if (typeof cellText[i] === 'string') {
if (row.childNodes[i].innerText != cellText[i]) {
row.childNodes[i].innerText = cellText[i];
}
} else if (cellText[i] instanceof Element) {
row.childNodes[i].appendChild = cellText[i];
} else {
if (row.childNodes[i].innerText != 'null') {
row.childNodes[i].innerText = 'null';
}
}
}
}
addRow(body, dataCell) {
const row = document.createElement('tr');
this.setCell(row, this.#colsLength, dataCell);
body.appendChild(row);
}
addMultiRow(body, dataCell = ['null']) {
// Remove unnecessary rows
for (let i = body.childNodes.length - 1; body.childNodes.length - 1 > dataCell.length; i--) {
let row = body.childNodes[i];
if (row && row.tagName === 'TR') {
row.remove();
}
}
//adding rows
for (let i = 0; i < dataCell.length; i++) {
this.addRow(body, dataCell[i]);
}
}
/* ///////////// Attributes ///////////// */
static get observedAttributes() {
return ['cols', 'rows'];
}
attributeChangedCallback(name, oldValue, newValue) {
let len;
switch (name) {
case 'cols':
len = parseInt(newValue);
if (len !== NaN && this.#colsLength !== len && newValue != oldValue) {
this.setColumn(new Array(len));
}
break;
case 'rows':
len = parseInt(newValue);
if (len !== NaN && newValue != oldValue) {
const rows = new Array(len).fill(new Array(len).fill('1'));
this.addMultiRow(this.tbody, rows);
}
break;
default:
break;
}
}
/* // GETTER & SETTER // */
get length() {
return this.#colsLength;
}
get cols() {
return this.getAttribute('cols');
}
get rows() {
return this.getAttribute('rows');
}
set cols(num) {
this.setAttribute('cols', num);
}
set rows(num) {
this.setAttribute('rows', num);
}
}
customElements.define('better-table', betterTable);
* {
margin: 0;
padding: 0;
}
/* //////////////////////////////////////// */
/* //////////// Global Style ////////////// */
/* //////////////////////////////////////// */
/* /// The Table Itself /// */
better-table {
width: 100%;
height: 100%;
}
table {
width: 100%;
height: 100%;
display: table;
box-sizing: border-box;
}
table thead,
table tbody,
table tr {
width: 100%;
display: table;
table-layout: fixed;
}
table tbody tr {
border-bottom: 1px solid black;
}
table th,
table td {
padding: 12px 15px;
overflow-x: hidden;
}
/* //////////////////////////////////////// */
/* //////////////////////////////////////// */
/* ///////// Header/Column Style ////////// */
/* //////////////////////////////////////// */
/* /// Header/Column row style /// */
table thead {
background: #f38181;
}
table thead tr {
position: sticky;
top: 0;
text-align: center;
}
/* //////////////////////////////////////// */
/* //////////////////////////////////////// */
/* /////// Body/Row Contents Style //////// */
/* //////////////////////////////////////// */
table tbody {
display: block;
overflow: hidden;
table-layout: fixed;
max-height: 65vh;
}
/* /// even row /// */
table tbody tr {
text-align: center;
background-color: #fddfdf;
color: #000;
}
/* /// odd row /// */
table tbody tr:nth-child(even) {
background-color: #eba4a4;
color: #000;
}
/* //////////////////////////////////////// */
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<link rel="stylesheet" href="table.css" />
<script defer type="module" src="./table.js"></script>
</head>
<body>
<style>
html,
body {
width: 100%;
height: 100%;
overflow: hidden;
}
.content {
width: 100%;
height: 500px;
}
.box {
position: absolute;
left: 20px;
bottom: 50px;
}
</style>
<div class="content">
<better-table cols="4" rows="10" lang="heb"></better-table>
</div>
</body>
</html>