The table component is one of the more complex components in front-end development, mainly because people have different needs for the table component. I have never seen a table component that can cover everyone’s needs.

From a business scenario perspective, table components can be divided into three types:

  • Bootstrap class: A table that can be implemented with CSS, mainly used on the page of the information presentation class.
  • In the background class: focus on the display, edit through the button to operate, mainly used in the background system. Compared with the table of Bootstrap class, a big demarcation point is the function of fixing table headers and columns.
  • Excel class: It focuses on editing, mainly online data editing scenarios, which are relatively niche. This type of table component is more performance demanding and has some unique features compared to the previous two types, such as the ability to double click inline editing, fixed rows, and so on.

For requirements that apply to Bootstrap class tables, it is recommended that you use the method provided by Bootstrap. For the table component of the middle and back classes, there are several common requirements:

  1. Fixed table header
  2. Fixed column
  3. row
  4. Table header sorting, table header filtering, multi-level table header
  5. Single selection, multiple selection

The most interesting of these features is probably the fixed table header and fixed column implementations. This article will focus on the different implementations of these two features and which implementation should be chosen.

The content and examples in this article do not use any framework, so if you are familiar with HTML, CSS, and jQuery, you should be able to read them in theory.

Start with a simple table

To ease your reading barriers, online examples of both feature implementations are available. Each of the online examples is done with modifications to the simplest Bootstrap 3.0 table, which can be viewed here.

Fixed table header implementation

If the data in the table has scroll bars, users will want the table head to be fixed at the top when scrolling, otherwise they will not be able to see the corresponding meaning of the cell data.

Browsers’

cannot display scroll bars, and even if they could, there is no way to prevent

from scrolling, while can scroll.

The simplest idea is to use two

, one to display the table header and one to display the table contents. Use another element to wrap
around the table contents, and set overflow: Auto to display the scroll bar. The implementation is shown in the figure below:

According to this idea quickly implemented a version, you can click here to view.

This version has a very obvious problem, is the table header and the table content column width is not consistent, will occur dislocation situation. The reason for the mismatch is as follows: the table content needs to display a scroll bar, the table header does not need to display a scroll bar, so there is a width difference between the two widths. It would be common to add an extra element on the top of the table to bridge the gap. This element would be called the Gutter.

The modified implementation mode is shown in the figure below:


The revised version can be viewed online directly, as shown below:


In addition to Gutter, there are some other instances that need to be explained, so four arrows have been added. Here are some explanations for each.

The realization of the Gutter

Gutter is defined as explained above, with the Gutter at arrow 1. See the th. Gutter element in the sample HTML and the style definition for the th. In a real scenario, this Gutter width would vary depending on the browser and operating system and would need to be calculated dynamically. The implementation code is as follows:

<th class="gutter"></th> /** Header right side space */. Custom-table th. Gutter {width: 15px; padding: 0; }Copy the code

Implementation of the right border

In the Gutter, the right side of the table will not display properly because of the Gutter. In this example, the pseudo-element before is used to add a right border to the outermost element. The implementation code is as follows:

Custom -table::before {content: ""; display: block; position: absolute; top: 0; bottom: 0; right: 0; border-right: 1px solid #ddd; }Copy the code

Bottom border implementation

The bottom border is at arrow 3. The original bottom border is displayed on

. After the scroll bar is added to the parent element of
, the bottom border of
is not displayed. You need to add a bottom border to the outermost element to compensate for the lack of a border. In this example, the pseudo-element before is used to add a right border to the outermost element. The implementation code is as follows:
Custom -table::after {content: ""; display: block; height: 0px; position: relative; top: -1px; border-bottom: 1px solid #ddd; }Copy the code

Consistent column width

Because the table header and table contents are now two separate

elements, synchronization of the column widths of the two becomes an issue. In this example, we can fix the problem by setting the table-layout property to FIXED.
.custom-table .table {
  table-layout: fixed;
  margin-bottom: 0;
}
Copy the code

For an explanation of table-layout, please refer to this article. In a nutshell, the two values of table-layout work as follows:

  • Auto: The width of the cell is adjusted according to the content.
  • Fixed:<table>or<col>If not, by the width of the cell in the first row.

It is impossible to solve the problem only by setting table-layout as fixed, and the modified style will continue to produce dislocation. You can refer to this example. In this example, the first TD in the first row of the table content is simply added with a width attribute, resulting in a mismatch between the table header and the table content.

Add a < COL > element to

, set the width property on the < COL > element, and dynamically synchronize the width of the table header with the col> element of the table content.

Due to space constraints, I will not repeat the code to achieve this function, if you are interested in implementing your own try.

Fixed column

The fixed table header is realized by dividing the table header and the table content into two

. The realization of the fixed column is essentially to clone the table header and the table content required by the fixed column. The implementation principle is shown in the figure below. The head and body of the table used for fixed columns are represented in dark color:

To simplify the example, the implementation of this example adds two prerequisites:

  1. The row height of each row in the table is uniform.
  2. The columns of the fixed column have a fixed width, fixed to 80.

The fixed column implementation relies on the fixed header implementation, so is modified from the fixed header example and can be viewed online. The example effect is shown below:


As the arrow above shows, there are three steps to achieve this effect:

  1. Render fixed column
  2. Synchronous Scroll event
  3. Synchronous hover effect

Render fixed column

First render the table headers and contents of the fixed columns in HTML:

<div class="custom-table--fixed-wrapper"> <div class="custom-table--header-wrapper"> <table class = "table table-bordered"> <tr> <th> Game ID </th> </tr> </table> </div> <div class="custom-table--body-wrapper is-fixed" style="height: 300px;" > <table class = "table table-hover table-bordered"> <tr> <td> 1 </td> </tr> <tr> <td> 2 </td> </tr> <tr> <td> 13 </td> </tr> <tr> <td> 1 </td> </tr> <tr> <td> 2 </td> </tr> <tr> <td> 13 </td> </tr> <tr> <td> 1 </td> </tr> <tr> <td> 2 </td>  </tr> <tr> <td> 13 </td> </tr> <tr> <td> 1 </td> </tr> <tr> <td> 2 </td> </tr> <tr> <td> 13 </td> </tr> </table> </div>  </div>Copy the code

Then add the following styles for the fixed column:

.custom-table--body-wrapper.is-fixed { overflow-y: hidden; }. Custom-table --fixed-wrapper {box-shadow:4px 0px 4px rgba(0, 0, 0, 0.1); position: absolute; left: 0; top: 0; bottom: 0; width: 81px; background-color: #fff; } .custom-table td, .custom-table th { white-space: nowrap; overflow: hidden; height: 42px; padding: 2px ! important; }Copy the code

Synchronous Scroll event

Because the fixed column and table body scroll bars are independent, when the table body scrolls, it needs to be synchronized to the fixed column table content scroll bar. The code implemented using jQuery is as follows:

$('.custom-table--body-wrapper'). On ('scroll', function(event) {var scrollTop = $(this).prop('scrollTop'); $('.custom-table--body-wrapper.is-fixed').prop('scrollTop', scrollTop); });Copy the code

Synchronous hover effect

The synchronous hover effect will be more troublesome, because in addition to the body of the table to hover will affect the fixed column, the fixed column hover also affect the body of the table. Since the Bootstrap hover effect uses :hover, we need to add a class that uses hover:

.custom-table tbody > tr.hover > td {
  background-color: #f5f5f5;
}
Copy the code

The JavaScript code to implement the synchronous hover effect is as follows:

var getRowIndex = function(event) { var target = event.target; if (target.tagName === 'TR') { return $(target).index(); } else { return $(event.target).parent('tr').index(); }}; $('.custom-table--body-wrapper tr'). Hover (function(event) {var index = getRowIndex(event); $('.custom-table--body-wrapper tr:nth-child(' + (index + 1) + ')').addClass('hover'); }, function(event) { var index = getRowIndex(event); $('.custom-table--body-wrapper tr:nth-child(' + (index + 1) + ')').removeClass('hover'); });Copy the code

Break through the limit

There are two limitations to this example, and here are the reasons:

  1. The row height of each row of the table is uniform: because the table content of the fixed column in this example only renders one column, the row height of the fixed column is controlled by that column. However, the row height in the body of the table is controlled by all the rows, and CSS cannot be used to achieve a high degree of synchronization between two unrelated elements.
  2. Fixed column columns have fixed widths: Since the column width of the body of the table is determined by the width of the table, fixed columns render only one column, and there is no CSS to synchronize the column width of the body of the table.

There are generally two options for breaking through these two limitations:

  1. Dynamically synchronize row height and column width on the left and right sides: The advantage is better performance, rendering only the columns that need to be rendered. The disadvantage is that it is difficult to control the timing of the same walking height and column width. There will be some edge cases that lead to bugs, such as the dislocation caused by inconsistent column width and row height.
  2. Fixed columns overlaid on the body of the table render all columns: the advantage is that there is no need to dynamically synchronize the walking heights and column widths, leaving the browser to control the row heights and column widths itself, making misalignment less likely. The disadvantage is also obvious, that is, in the case of large amount of data or complex rendering content in the table, it will lead to too many times of rendering, resulting in certain performance problems.

BTW, table components do not necessarily need to break through these two limitations, sometimes they are necessary, depending on the actual business scenario. For Excel table components, the fixed row height is the basis for ensuring component performance, and this limitation also makes some other features easier to implement.

Write in the last

Implementing complex components has always been a niche job for front-end programmers. Partly because of the difficulty of implementation and partly because of the low input-output ratio, it is better to use open source products or commercial products directly.

If you’re interested in implementing a table component yourself, hopefully this article will help. If you have any questions about this article, please leave them in the comments section.

Finally, thank you for your patience to read this article.