[转]AngularJS fixed header scrollable table directive

令狐烨烨
2023-12-01

本文转自:http://pointblankdevelopment.com.au/blog/angularjs-fixed-header-scrollable-table-directive

 

This post contains a custom AngularJS directive you can use to give your html table a fixed header and footer with a scrollable body, we developed it for a law firm marketing website recently, it uses a pure CSS approach and doesn't touch any of the html tags, leaving the html table completely intact and happily semantic :)

Creating a fixed header scrollable table using purely CSS turns out to be a surprisingly tricky thing to do, in an ideal world I thought it would just be a matter of setting the height of the table body and "overflow:hidden", but there turns out to be a bit more to it than that, especially if you have a table that contains dynamic content because the width of each column in the thead and tbody need to be set in order for it to continue looking like a table and not just a big mess.

In a nutshell the CSS changes that need to happen are:

  • Set the width of each column in the thead and tbody, making sure they match up so the columns aren't wonky
  • Set the thead and tbody to "display:block;"
  • Set the tbody height and "overflow:auto;" to add the scrollbar
  • When there's a scrollbar (when the tbody content overflows it's height), reduce the width of the final column in the tbody by the width of the scrollbar

Here's the solution I came up with:

The fixedHeader AngularJS directive

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
/**
  * AngularJS fixed header scrollable table directive
  * @author Jason Watmore <jason@pointblankdevelopment.com.au> (http://jasonwatmore.com)
  * @version 1.2.0
  */
( function () {
     angular
         .module( 'anguFixedHeaderTable' , [])
         .directive( 'fixedHeader' , fixedHeader);
 
     fixedHeader.$inject = [ '$timeout' ];
 
     function fixedHeader($timeout) {
         return {
             restrict: 'A' ,
             link: link
         };
 
         function link($scope, $elem, $attrs, $ctrl) {
             var elem = $elem[0];
 
             // wait for data to load and then transform the table
             $scope.$watch(tableDataLoaded, function (isTableDataLoaded) {
                 if (isTableDataLoaded) {
                     transformTable();
                 }
             });
 
             function tableDataLoaded() {
                 // first cell in the tbody exists when data is loaded but doesn't have a width
                 // until after the table is transformed
                 var firstCell = elem.querySelector('tbody tr:first-child td:first-child ');
                 return firstCell && !firstCell.style.width;
             }
 
             function transformTable() {
                 // reset display styles so column widths are correct when measured below
                 angular.element(elem.querySelectorAll(' thead, tbody, tfoot ')).css(' display ', ' ');
 
                 // wrap in $timeout to give table a chance to finish rendering
                 $timeout(function () {
                     // set widths of columns
                     angular.forEach(elem.querySelectorAll(' tr:first-child th '), function (thElem, i) {
 
                         var tdElems = elem.querySelector(' tbody tr:first-child td:nth-child( ' + (i + 1) + ' ) ');
                         var tfElems = elem.querySelector(' tfoot tr:first-child td:nth-child( ' + (i + 1) + ' ) ');
 
                         var columnWidth = tdElems ? tdElems.offsetWidth : thElem.offsetWidth;
                         if (tdElems) {
                             tdElems.style.width = columnWidth + ' px ';
                         }
                         if (thElem) {
                             thElem.style.width = columnWidth + ' px ';
                         }
                         if (tfElems) {
                             tfElems.style.width = columnWidth + ' px ';
                         }
                     });
 
                     // set css styles on thead and tbody
                     angular.element(elem.querySelectorAll(' thead, tfoot ')).css(' display ', ' block ');
 
                     angular.element(elem.querySelectorAll(' tbody ')).css({
                         ' display ': ' block ',
                         ' height ': $attrs.tableHeight || ' inherit ',
                         ' overflow ': ' auto '
                     });
 
                     // reduce width of last column by width of scrollbar
                     var tbody = elem.querySelector(' tbody ');
                     var scrollBarWidth = tbody.offsetWidth - tbody.clientWidth;
                     if (scrollBarWidth > 0) {
                         // for some reason trimming the width by 2px lines everything up better
                         scrollBarWidth -= 2;
                         var lastColumn = elem.querySelector(' tbody tr:first-child td:last-child ');
                         lastColumn.style.width = (lastColumn.offsetWidth - scrollBarWidth) + ' px';
                     }
                 });
             }
         }
     }
})();

 

Sample HTML that uses the fixed-header directive

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
< table class = "table table-bordered" fixed-header>
     < thead >
         < tr >
             < th >Header 1</ th >
             < th >Header 2</ th >
             < th >Header 3</ th >
             < th >Header 4</ th >
         </ tr >
     </ thead >
     < tbody >
         < tr ng-repeat = "item in [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]" >
             < td >Row {{item}} Col 1</ td >
             < td >Row {{item}} Col 2</ td >
             < td >Row {{item}} Col 3</ td >
             < td >Row {{item}} Col 4</ td >
         </ tr >
     </ tbody >
     < tfoot >
         < tr >
             < td >Footer 1</ td >
             < td >Footer 2</ td >
             < td >Footer 3</ td >
             < td >Footer 4</ td >
         </ tr >
     </ tfoot >
</ table >

The default height of the table body is 400px, to change this add a table-height attribute to the table element eg: table-height="500px".

UPDATE 08/10/2014: Added support for fixed footer (tfoot) element.

 

转载于:https://www.cnblogs.com/freeliver54/p/5234817.html

 类似资料: