bootstrap-table-sticky-header.js 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. /**
  2. * @author vincent loh <vincent.ml@gmail.com>
  3. * @update J Manuel Corona <jmcg92@gmail.com>
  4. * @update zhixin wen <wenzhixin2010@gmail.com>
  5. */
  6. const Utils = $.fn.bootstrapTable.utils
  7. $.extend($.fn.bootstrapTable.defaults, {
  8. stickyHeader: false,
  9. stickyHeaderOffsetY: 0,
  10. stickyHeaderOffsetLeft: 0,
  11. stickyHeaderOffsetRight: 0
  12. })
  13. const hiddenClass = {
  14. bootstrap3: 'hidden'
  15. }[$.fn.bootstrapTable.theme] || 'd-none'
  16. $.BootstrapTable = class extends $.BootstrapTable {
  17. initHeader (...args) {
  18. super.initHeader(...args)
  19. if (!this.options.stickyHeader) {
  20. return
  21. }
  22. this.$el.before('<div class="sticky-header-container"></div>')
  23. this.$el.before('<div class="sticky_anchor_begin"></div>')
  24. this.$el.after('<div class="sticky_anchor_end"></div>')
  25. this.$header.addClass('sticky-header')
  26. // clone header just once, to be used as sticky header
  27. // deep clone header, using source header affects tbody>td width
  28. this.$stickyContainer = this.$tableBody.find('.sticky-header-container')
  29. this.$stickyBegin = this.$tableBody.find('.sticky_anchor_begin')
  30. this.$stickyEnd = this.$tableBody.find('.sticky_anchor_end')
  31. this.$stickyHeader = this.$header.clone(true, true)
  32. // render sticky on window scroll or resize
  33. $(window).off('resize.sticky-header-table')
  34. .on('resize.sticky-header-table', () => this.renderStickyHeader())
  35. $(window).off('scroll.sticky-header-table')
  36. .on('scroll.sticky-header-table', () => this.renderStickyHeader())
  37. this.$tableBody.off('scroll').on('scroll', () => this.matchPositionX())
  38. }
  39. onColumnSearch ({currentTarget, keyCode}) {
  40. super.onColumnSearch({currentTarget, keyCode})
  41. this.renderStickyHeader()
  42. }
  43. resetView (...args) {
  44. super.resetView(...args)
  45. $('.bootstrap-table.fullscreen').off('scroll')
  46. .on('scroll', () => this.renderStickyHeader())
  47. }
  48. renderStickyHeader () {
  49. const that = this
  50. this.$stickyHeader = this.$header.clone(true, true)
  51. if (this.options.filterControl) {
  52. $(this.$stickyHeader).off('keyup change mouseup').on('keyup change mouse', function (e) {
  53. const $target = $(e.target)
  54. const value = $target.val()
  55. const field = $target.parents('th').data('field')
  56. const $coreTh = that.$header.find('th[data-field="' + field + '"]')
  57. if ($target.is('input')) {
  58. $coreTh.find('input').val(value)
  59. } else if ($target.is('select')) {
  60. const $select = $coreTh.find('select')
  61. $select.find('option[selected]').removeAttr('selected')
  62. $select.find('option[value="' + value + '"]').attr('selected', true)
  63. }
  64. that.triggerSearch()
  65. })
  66. }
  67. const top = $(window).scrollTop()
  68. // top anchor scroll position, minus header height
  69. const start = this.$stickyBegin.offset().top - this.options.stickyHeaderOffsetY
  70. // bottom anchor scroll position, minus header height, minus sticky height
  71. const end = this.$stickyEnd.offset().top - this.options.stickyHeaderOffsetY - this.$header.height()
  72. // show sticky when top anchor touches header, and when bottom anchor not exceeded
  73. if (top > start && top <= end) {
  74. // ensure clone and source column widths are the same
  75. this.$stickyHeader.find('tr:eq(0)').find('th').each((index, el) => {
  76. $(el).css('min-width', this.$header.find('tr:eq(0)').find('th').eq(index).css('width'))
  77. })
  78. // match bootstrap table style
  79. this.$stickyContainer.removeClass(hiddenClass).addClass('fix-sticky fixed-table-container')
  80. // stick it in position
  81. let stickyHeaderOffsetLeft = this.options.stickyHeaderOffsetLeft
  82. let stickyHeaderOffsetRight = this.options.stickyHeaderOffsetRight
  83. if (this.$el.closest('.bootstrap-table').hasClass('fullscreen')) {
  84. stickyHeaderOffsetLeft = 0
  85. stickyHeaderOffsetRight = 0
  86. }
  87. this.$stickyContainer.css('top', `${this.options.stickyHeaderOffsetY}`)
  88. this.$stickyContainer.css('left', `${stickyHeaderOffsetLeft}`)
  89. this.$stickyContainer.css('right', `${stickyHeaderOffsetRight}`)
  90. // create scrollable container for header
  91. this.$stickyTable = $('<table/>')
  92. this.$stickyTable.addClass(this.options.classes)
  93. // append cloned header to dom
  94. this.$stickyContainer.html(this.$stickyTable.append(this.$stickyHeader))
  95. // match clone and source header positions when left-right scroll
  96. this.matchPositionX()
  97. } else {
  98. this.$stickyContainer.removeClass('fix-sticky').addClass(hiddenClass)
  99. }
  100. }
  101. matchPositionX () {
  102. this.$stickyContainer.scrollLeft(this.$tableBody.scrollLeft())
  103. }
  104. }