Czy możemy mieć wielu <tbody> w tej samej <table>?

594

Czy możemy mieć wiele <tbody>tagów w jednym <table>? Jeśli tak, to w jakich scenariuszach powinniśmy używać wielu <tbody>tagów?

Jitendra Vyas
źródło

Odpowiedzi:

710

Tak, możesz ich użyć, na przykład ja używam ich do łatwiejszego stylizowania grup danych, takich jak to:

thead th { width: 100px; border-bottom: solid 1px #ddd; font-weight: bold; }
tbody:nth-child(odd) { background: #f5f5f5;  border: solid 1px #ddd; }
tbody:nth-child(even) { background: #e5e5e5;  border: solid 1px #ddd; }
<table>
    <thead>
        <tr><th>Customer</th><th>Order</th><th>Month</th></tr>
    </thead>
    <tbody>
        <tr><td>Customer 1</td><td>#1</td><td>January</td></tr>
        <tr><td>Customer 1</td><td>#2</td><td>April</td></tr>
        <tr><td>Customer 1</td><td>#3</td><td>March</td></tr>
    </tbody>
    <tbody>
        <tr><td>Customer 2</td><td>#1</td><td>January</td></tr>
        <tr><td>Customer 2</td><td>#2</td><td>April</td></tr>
        <tr><td>Customer 2</td><td>#3</td><td>March</td></tr>
    </tbody>
    <tbody>
        <tr><td>Customer 3</td><td>#1</td><td>January</td></tr>
        <tr><td>Customer 3</td><td>#2</td><td>April</td></tr>
        <tr><td>Customer 3</td><td>#3</td><td>March</td></tr>
    </tbody>
</table>

Możesz zobaczyć przykład tutaj . Działa tylko w nowszych przeglądarkach, ale to właśnie obsługuję w mojej obecnej aplikacji, możesz użyć grupowania dla JavaScript itp. Najważniejsze jest to wygodny sposób wizualnego grupowania wierszy, aby dane były znacznie bardziej czytelne . Istnieją oczywiście inne zastosowania, ale jeśli chodzi o odpowiednie przykłady, ten jest dla mnie najbardziej powszechny.

Nick Craver
źródło
6
ok dzięki za świetną odpowiedź. Czy to ma znaczenie dla czytnika ekranu, jednego tbodyczy wielu?
Jitendra Vyas,
1
@ metal-gear-solid - Z mojego doświadczenia wynika, że ​​dobrze sobie z nimi radzą, np .: jakby byli jednym <tbody>. Kiedy zaczynasz zagnieżdżać tabele, zwykle powoduje to prawdziwe problemy z nawigacją dla czytnika ekranu.
Nick Craver
10
@metal: nie, istnieje różnica semantyczna - wiele <tbody>elementów opisuje oddzielne grupy w tabeli, jak wyjaśniono w odpowiedzi. Powinienem również dodać, że ogólnie lepiej jest kierować komórki na tła, więc CSS powinien być na przykładtbody:nth-child(odd) td { background: #f5f5f5; }
DisgruntledGoat
4
Jaka jest definicja „nowszych przeglądarek”?
Tim Down
8
@TimDown - kiedy powiedziałem, że „nowsze przeglądarki” odnosiły się tylko do :nth-child()użycia CSS w połączonej demonstracji, wielokrotność <tbody>będzie działać w dowolnej przeglądarce.
Nick Craver
298

Tak. Z DTD

<!ELEMENT table
     (caption?, (col*|colgroup*), thead?, tfoot?, (tbody+|tr+))>

Więc oczekuje jednego lub więcej. Następnie mówi dalej

Użyj wielu sekcji tbody, gdy potrzebne są reguły między grupami wierszy tabeli.

Martin Smith
źródło
12
W specyfikacji HTML5 to się nieznacznie zmienia, ale podstawowe „tak, wiele tbodyelementów jest w porządku) pozostaje. W szczególności możesz teraz umieścić jeden tfootelement po tym, tbodyjeśli chcesz . (Zręcznie przesunęły się w stronę DTD mówiąc, że nie zapewniają .) :-)
TJ Crowder
5
Dziękuję za tę odpowiedź. Odwoływanie się do specyfikacji to odpowiedź nr 1 w mojej książce.
KernelCurry
1
Więc oczekuje jednego lub więcej. To źle, może to być zbiór, <tr>więc może to być również zero (tzn. Osoba lub tr oznacza, że ​​może to być tr i nie ma osoby).
Alexis Wilke
@AlexisWilke jest to zgodne ze specyfikacją: Tag startowy TBODY jest zawsze wymagany, z wyjątkiem sytuacji, gdy stół zawiera tylko jeden korpus stołu i nie ma sekcji stołu ani stóp
Gecko IT,
14

Problem Martina Joinera jest spowodowany niezrozumieniem <caption>tagu.

<caption>Tag definiuje podpis tabeli.

<caption>Tag musi być pierwszym dzieckiem <table>tagu.

Możesz podać tylko jeden podpis na tabelę.

Należy również pamiętać, że scopeatrybut należy umieścić na <th>elemencie, a nie na <tr>elemencie.

Właściwy sposób napisania tabeli z wieloma nagłówkami i wieloma osobami to coś takiego:

<table id="dinner_table">
    <caption>This is the only correct place to put a caption.</caption>
    <tbody>
        <tr class="header">
            <th colspan="2" scope="col">First Half of Table (British Dinner)</th>
        </tr>
        <tr>
            <th scope="row">1</th>
            <td>Fish</td>
        </tr>
        <tr>
            <th scope="row">2</th>
            <td>Chips</td>
        </tr>
        <tr>
            <th scope="row">3</th>
            <td>Peas</td>
        </tr>
        <tr>
            <th scope="row">4</th>
            <td>Gravy</td>
        </tr>
    </tbody>
    <tbody>
        <tr class="header">
            <th colspan="2" scope="col">Second Half of Table (Italian Dinner)</th>
        </tr>
        <tr>
            <th scope="row">5</th>
            <td>Pizza</td>
        </tr>
        <tr>
            <th scope="row">6</th>
            <td>Salad</td>
        </tr>
        <tr>
            <th scope="row">7</th>
            <td>Oil</td>
        </tr>
        <tr>
            <th scope="row">8</th>
            <td>Bread</td>
        </tr>
    </tbody>
</table>

John Slegers
źródło
captionTag powinien postępować otwarcie tabletag. developer.mozilla.org/en-US/docs/Web/HTML/Element/table
Cypher
Masz rację. Jakoś źle zinterpretowałem dokumenty. Naprawiłem błąd.
John Slegers
Spec zaleca użycie scope="rowgroup"(zamiast col) tbodynagłówków. Zobacz przykład .
CletusW
7

Tak. Używam ich do dynamicznego ukrywania / odsłaniania odpowiedniej części stołu, np. Kursu. Mianowicie.

<table>
  <tbody id="day1" style="display:none">
    <tr><td>session1</td><tr>
    <tr><td>session2</td><tr>
  </tbody>
  <tbody id="day2">
    <tr><td>session3</td><tr>
    <tr><td>session4</td><tr>
  </tbody>
  <tbody id="day3" style="display:none">
    <tr><td>session5</td><tr>
    <tr><td>session6</td><tr>
  </tbody>
</table>

Można udostępnić przycisk do przełączania między wszystkim lub tylko bieżącym dniem, manipulując tbodies bez przetwarzania wielu wierszy osobno.

CPslashM
źródło
4

EDYCJA: captionTag należy do tabeli i dlatego powinien istnieć tylko raz. Nie kojarz captionz każdym tbodyelementem tak jak ja:

<table>
    <caption>First Half of Table (British Dinner)</caption>
    <tbody>
        <tr><th>1</th><td>Fish</td></tr>
        <tr><th>2</th><td>Chips</td></tr>
        <tr><th>3</th><td>Pease</td></tr>
        <tr><th>4</th><td>Gravy</td></tr>
    </tbody>
    <caption>Second Half of Table (Italian Dinner)</caption>
    <tbody>
        <tr><th>5</th><td>Pizza</td></tr>
        <tr><th>6</th><td>Salad</td></tr>
        <tr><th>7</th><td>Oil</td></tr>
        <tr><th>8</th><td>Bread</td></tr>
    </tbody>
</table>

ZŁY PRZYKŁAD POWYŻSZY: NIE KOPIUJ

Powyższy przykład nie wyświetla się tak, jak można się spodziewać, ponieważ takie pisanie wskazuje na nieporozumienie captionznacznika. Będziesz potrzebował wielu hacków CSS, aby był poprawnie renderowany, ponieważ byłbyś niezgodny ze standardami.

Szukałem standardów W3C w captiontagu, ale nie mogłem znaleźć wyraźnej reguły, która mówi, że musi być tylko jeden captionelement na tabelę, ale tak jest w rzeczywistości.

Martin Joiner
źródło
3

Ponadto, jeśli uruchomisz dokument HTML z wieloma <tbody>znacznikami poprzez W3C's HTML Validator , z HTML5 DOCTYPE, zostanie pomyślnie sprawdzony.

Berno
źródło
2

Utworzyłem JSFiddle, w którym mam dwa zagnieżdżone powtórzenia ng z tabelami i nadrzędne ng-powtórzenie na tbody. Jeśli przejrzysz dowolny wiersz w tabeli, zobaczysz, że istnieje sześć elementów tbody, tj. Poziom nadrzędny.

HTML

<div>
        <table class="table table-hover table-condensed table-striped">
            <thead>
                <tr>
                    <th>Store ID</th>
                    <th>Name</th>
                    <th>Address</th>
                    <th>City</th>
                    <th>Cost</th>
                    <th>Sales</th>
                    <th>Revenue</th>
                    <th>Employees</th>
                    <th>Employees H-sum</th>
                </tr>
            </thead>
            <tbody data-ng-repeat="storedata in storeDataModel.storedata">
                <tr id="storedata.store.storeId" class="clickableRow" title="Click to toggle collapse/expand day summaries for this store." data-ng-click="selectTableRow($index, storedata.store.storeId)">
                    <td>{{storedata.store.storeId}}</td>
                    <td>{{storedata.store.storeName}}</td>
                    <td>{{storedata.store.storeAddress}}</td>
                    <td>{{storedata.store.storeCity}}</td>
                    <td>{{storedata.data.costTotal}}</td>
                    <td>{{storedata.data.salesTotal}}</td>
                    <td>{{storedata.data.revenueTotal}}</td>
                    <td>{{storedata.data.averageEmployees}}</td>
                    <td>{{storedata.data.averageEmployeesHours}}</td>
                </tr>
                <tr data-ng-show="dayDataCollapse[$index]">
                    <td colspan="2">&nbsp;</td>
                    <td colspan="7">
                        <div>
                            <div class="pull-right">
                                <table class="table table-hover table-condensed table-striped">
                                    <thead>
                                        <tr>
                                            <th></th>
                                            <th>Date [YYYY-MM-dd]</th>
                                            <th>Cost</th>
                                            <th>Sales</th>
                                            <th>Revenue</th>
                                            <th>Employees</th>
                                            <th>Employees H-sum</th>
                                        </tr>
                                    </thead>
                                    <tbody>
                                        <tr data-ng-repeat="dayData in storeDataModel.storedata[$index].data.dayData">
                                            <td class="pullright">
                                                <button type="btn btn-small" title="Click to show transactions for this specific day..." data-ng-click=""><i class="icon-list"></i>
                                                </button>
                                            </td>
                                            <td>{{dayData.date}}</td>
                                            <td>{{dayData.cost}}</td>
                                            <td>{{dayData.sales}}</td>
                                            <td>{{dayData.revenue}}</td>
                                            <td>{{dayData.employees}}</td>
                                            <td>{{dayData.employeesHoursSum}}</td>
                                        </tr>
                                    </tbody>
                                </table>
                            </div>
                        </div>
                    </td>
                </tr>
            </tbody>
        </table>
    </div>

(Uwaga dodatkowa: to wypełnia DOM, jeśli masz dużo danych na obu poziomach, dlatego pracuję nad dyrektywą w celu pobierania danych i zastępowania, tj. Dodawania do DOM po kliknięciu elementu nadrzędnego i usuwania po kliknięciu innego lub tego samego elementu nadrzędnego ponownie. Aby uzyskać takie zachowanie, jakie można znaleźć na Prisjakt.nu , przewiń w dół do wymienionych komputerów i kliknij wiersz (nie łącza). Jeśli to zrobisz i sprawdzisz elementy, zobaczysz, że tr jest dodany i a następnie usuwane, jeśli rodzic zostanie ponownie kliknięty).

Pixic
źródło