Элемент пользовательской таблицы JS всегда отсутствует 1 строка

Я создал собственный элемент TABLE, и он обновляет количество строк по атрибуту «строки», но отсутствует одна строка,

Например: я установил rows='10', выходных строк будет 9.

Я знаю, что если я удалю элемент div, который я добавил в «TBODY», проблема будет решена, но я хочу, чтобы он был в «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>
Стилизация и валидация html-формы без использования JavaScript (только HTML/CSS)
Стилизация и валидация html-формы без использования JavaScript (только HTML/CSS)
Будучи разработчиком веб-приложений, легко впасть в заблуждение, считая, что приложение без JavaScript не имеет права на жизнь. Нам становится удобно...
Введение в технологический стек Twitch
Введение в технологический стек Twitch
В этой статье мы подробно рассмотрим стек Twitch, который подразделяется на следующий набор технологий:
8 полезных HTML-тегов, которые лучше использовать вместо <div>
8 полезных HTML-тегов, которые лучше использовать вместо <div>
Когда я только начинал изучать html, я использовал div для всего, это был один из первых тегов, которые я выучил, и казалось, что он работает в любой...
HTML5: API локального хранилища (Local Storage)
HTML5: API локального хранилища (Local Storage)
LocalStorage - это простой способ хранения данных в браузере пользователя.
Доступность HTML - программирование с инклюзивной перспективой
Доступность HTML - программирование с инклюзивной перспективой
Представьте, что вы хотите поехать на пляж. Представьте, что вы упорно трудились весь год и заслужили это. Прибыв на место, вы обнаруживаете, что...
Именование классов CSS: Конвенция именования BEM
Именование классов CSS: Конвенция именования BEM
Сопровождаемость кода, сама по себе, является пульсирующим эффектом нескольких факторов. Когда часть программного обеспечения читабельна, ясна,...
0
0
22
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Эта логика вызывает проблему с добавлением строк

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>

Спасибо, я исправил это тем, что сравниваю последнюю созданную строку с выбранной строкой. Без того, что вы сказали, я, вероятно, не заметил бы эту ошибку. И я хочу, чтобы она не создавала новую строку, если она уже существует.

DDHost 09.04.2022 19:11

Другие вопросы по теме