Browse Source

Added right fixed columns support

zhixin 5 years ago
parent
commit
92c86e6511

+ 13 - 3
site/docs/extensions/fixed-columns.md

@@ -27,7 +27,7 @@ toc: true
 
 
 - **Detail:**
 - **Detail:**
 
 
-  set `true` to enable fixed columns.
+  Set `true` to enable fixed columns.
 
 
 - **Default:** `false`
 - **Default:** `false`
 
 
@@ -39,6 +39,16 @@ toc: true
 
 
 - **Detail:**
 - **Detail:**
 
 
-  the number of fixed columns.
+  The number of the left fixed columns.
 
 
-- **Default:** `1`
+- **Default:** `0`
+
+### fixedRightNumber
+
+- **type:** Number
+
+- **Detail:**
+
+  The number of the right fixed columns.
+
+- **Default:** `0`

+ 5 - 3
src/bootstrap-table.js

@@ -1987,15 +1987,17 @@ class BootstrapTable {
     // horizontal scroll event
     // horizontal scroll event
     // TODO: it's probably better improving the layout than binding to scroll event
     // TODO: it's probably better improving the layout than binding to scroll event
     this.$tableBody.off('scroll').on('scroll', ({currentTarget}) => {
     this.$tableBody.off('scroll').on('scroll', ({currentTarget}) => {
+      const scrollLeft = this.$tableBody.scrollLeft()
+
       if (this.options.showHeader && this.options.height) {
       if (this.options.showHeader && this.options.height) {
-        this.$tableHeader.scrollLeft($(currentTarget).scrollLeft())
+        this.$tableHeader.scrollLeft(scrollLeft)
       }
       }
 
 
       if (this.options.showFooter && !this.options.cardView) {
       if (this.options.showFooter && !this.options.cardView) {
-        this.$tableFooter.scrollLeft($(currentTarget).scrollLeft())
+        this.$tableFooter.scrollLeft(scrollLeft)
       }
       }
 
 
-      this.trigger('scroll-body', $(currentTarget))
+      this.trigger('scroll-body', this.$tableBody)
     })
     })
   }
   }
 
 

+ 177 - 50
src/extensions/fixed-columns/bootstrap-table-fixed-columns.js

@@ -4,11 +4,37 @@
 
 
 $.extend($.fn.bootstrapTable.defaults, {
 $.extend($.fn.bootstrapTable.defaults, {
   fixedColumns: false,
   fixedColumns: false,
-  fixedNumber: 1
+  fixedNumber: 0,
+  fixedRightNumber: 0
 })
 })
 
 
 $.BootstrapTable = class extends $.BootstrapTable {
 $.BootstrapTable = class extends $.BootstrapTable {
 
 
+  initContainer () {
+    if (
+      this.options.fixedColumns &&
+      (this.options.fixedNumber || this.options.fixedRightNumber)
+    ) {
+      this.options.classes = this.options.classes.replace('table-hover', '')
+    }
+
+    super.initContainer()
+
+    if (!this.options.fixedColumns) {
+      return
+    }
+
+    if (this.options.fixedNumber) {
+      this.$tableContainer.append('<div class="fixed-columns"></div>')
+      this.$fixedColumns = this.$tableContainer.find('.fixed-columns')
+    }
+
+    if (this.options.fixedRightNumber) {
+      this.$tableContainer.append('<div class="fixed-columns-right"></div>')
+      this.$fixedColumnsRight = this.$tableContainer.find('.fixed-columns-right')
+    }
+  }
+
   fitHeader (...args) {
   fitHeader (...args) {
     super.fitHeader(...args)
     super.fitHeader(...args)
 
 
@@ -20,27 +46,30 @@ $.BootstrapTable = class extends $.BootstrapTable {
       return
       return
     }
     }
 
 
-    this.$container.find('.fixed-table-header-columns').remove()
-    this.$fixedHeader = $('<div class="fixed-table-header-columns"></div>')
-    this.$fixedHeader.append(this.$tableHeader.find('>table').clone(true))
-    this.$tableHeader.after(this.$fixedHeader)
+    this.needFixedColumns = this.$tableHeader.width() < this.$tableHeader.find('table').width()
 
 
-    const width = this.getFixedColumnsWidth()
+    if (this.needFixedColumns && this.options.fixedNumber) {
+      this.$fixedColumns.find('.fixed-table-header').remove()
+      this.$fixedColumns.append(this.$tableHeader.clone(true))
+      this.$fixedHeader = this.$fixedColumns.find('.fixed-table-header')
 
 
-    this.$fixedHeader.css({
-      top: 0,
-      width,
-      height: this.$tableHeader.outerHeight(true)
-    })
+      this.$fixedColumns.css({
+        width: this.getFixedColumnsWidth()
+      })
+    }
 
 
-    this.initFixedColumnsBody()
+    if (this.needFixedColumns && this.options.fixedRightNumber) {
+      this.$fixedColumnsRight.find('.fixed-table-header').remove()
+      this.$fixedColumnsRight.append(this.$tableHeader.clone(true))
+      this.$fixedHeaderRight = this.$fixedColumnsRight.find('.fixed-table-header')
 
 
-    this.$fixedBody.css({
-      top: this.$tableHeader.outerHeight(true),
-      width,
-      height: this.$tableBody.outerHeight(true) - 1
-    })
+      this.$fixedColumnsRight.css({
+        width: this.getFixedColumnsWidth(true)
+      })
+      this.$fixedHeaderRight.scrollLeft(this.$fixedHeaderRight.find('table').width())
+    }
 
 
+    this.initFixedColumnsBody()
     this.initFixedColumnsEvents()
     this.initFixedColumnsEvents()
   }
   }
 
 
@@ -56,58 +85,156 @@ $.BootstrapTable = class extends $.BootstrapTable {
     }
     }
 
 
     this.initFixedColumnsBody()
     this.initFixedColumnsBody()
-
-    this.$fixedBody.css({
-      top: 0,
-      width: this.getFixedColumnsWidth(),
-      height: this.$tableHeader.outerHeight(true) + this.$tableBody.outerHeight(true)
-    })
-
     this.initFixedColumnsEvents()
     this.initFixedColumnsEvents()
   }
   }
 
 
   initFixedColumnsBody () {
   initFixedColumnsBody () {
-    this.$container.find('.fixed-table-body-columns').remove()
-    this.$fixedBody = $('<div class="fixed-table-body-columns"></div>')
-    this.$fixedBody.append(this.$tableBody.find('>table').clone(true))
-    this.$tableBody.after(this.$fixedBody)
+    if (this.needFixedColumns && this.options.fixedNumber) {
+      this.$fixedColumns.find('.fixed-table-body').remove()
+      this.$fixedColumns.append(this.$tableBody.clone(true))
+      this.$fixedBody = this.$fixedColumns.find('.fixed-table-body')
+
+      this.$fixedBody.css({
+        height: this.$fixedColumns.height() - this.$fixedHeader.height()
+      })
+    }
+
+    if (this.needFixedColumns && this.options.fixedRightNumber) {
+      this.$fixedColumnsRight.find('.fixed-table-body').remove()
+      this.$fixedColumnsRight.append(this.$tableBody.clone(true))
+      this.$fixedBodyRight = this.$fixedColumnsRight.find('.fixed-table-body')
+
+      this.$fixedBodyRight.css({
+        height: this.$fixedColumnsRight.height() - this.$fixedHeaderRight.height()
+      })
+      this.$fixedBodyRight.scrollLeft(this.$fixedBodyRight.find('table').width())
+    }
   }
   }
 
 
-  getFixedColumnsWidth () {
-    const visibleFields = this.getVisibleFields()
+  getFixedColumnsWidth (isRight) {
+    let visibleFields = this.getVisibleFields()
     let width = 0
     let width = 0
+    let fixedNumber = this.options.fixedNumber
+
+    if (isRight) {
+      visibleFields = visibleFields.reverse()
+      fixedNumber = this.options.fixedRightNumber
+    }
 
 
-    for (let i = 0; i < this.options.fixedNumber; i++) {
+    for (let i = 0; i < fixedNumber; i++) {
       width += this.$header.find(`th[data-field="${visibleFields[i]}"]`).outerWidth(true)
       width += this.$header.find(`th[data-field="${visibleFields[i]}"]`).outerWidth(true)
     }
     }
 
 
     return width + 1
     return width + 1
   }
   }
 
 
-  initFixedColumnsEvents () {
-    // events
-    this.$tableBody.off('scroll.fixed-columns').on('scroll.fixed-columns', e => {
-      this.$fixedBody.find('table').css('top', -$(e.currentTarget).scrollTop())
-    })
+  trigger (...args) {
+    super.trigger(...args)
 
 
-    this.$body.find('> tr[data-index]').off('hover').hover(e => {
-      const index = $(e.currentTarget).data('index')
-      this.$fixedBody.find(`tr[data-index="${index}"]`)
-        .css('background-color', $(e.currentTarget).css('background-color'))
-    }, e => {
-      const index = $(e.currentTarget).data('index')
-      const $tr = this.$fixedBody.find(`tr[data-index="${index}"]`)
-      $tr.attr('style', $tr.attr('style').replace(/background-color:.*;/, ''))
-    })
+    if (args[0] === 'scroll-body') {
+      if (this.needFixedColumns && this.options.fixedNumber) {
+        this.$fixedBody.scrollTop(this.$tableBody.scrollTop())
+      }
+
+      if (this.needFixedColumns && this.options.fixedRightNumber) {
+        this.$fixedBodyRight.scrollTop(this.$tableBody.scrollTop())
+      }
+    }
+  }
 
 
-    this.$fixedBody.find('tr[data-index]').off('hover').hover(e => {
+  initFixedColumnsEvents () {
+    this.$tableBody.find('tr').hover(e => {
       const index = $(e.currentTarget).data('index')
       const index = $(e.currentTarget).data('index')
-      this.$body.find(`tr[data-index="${index}"]`)
-        .css('background-color', $(e.currentTarget).css('background-color'))
+      $(e.currentTarget).addClass('hover')
+
+      if (this.options.fixedNumber) {
+        this.$fixedBody.find(`tr[data-index="${index}"]`).addClass('hover')
+      }
+      if (this.options.fixedRightNumber) {
+        this.$fixedBodyRight.find(`tr[data-index="${index}"]`).addClass('hover')
+      }
     }, e => {
     }, e => {
       const index = $(e.currentTarget).data('index')
       const index = $(e.currentTarget).data('index')
-      const $tr = this.$body.find(`> tr[data-index="${index}"]`)
-      $tr.attr('style', $tr.attr('style').replace(/background-color:.*;/, ''))
+      $(e.currentTarget).removeClass('hover')
+
+      if (this.options.fixedNumber) {
+        this.$fixedBody.find(`tr[data-index="${index}"]`).removeClass('hover')
+      }
+      if (this.options.fixedRightNumber) {
+        this.$fixedBodyRight.find(`tr[data-index="${index}"]`).removeClass('hover')
+      }
     })
     })
+
+    if (this.needFixedColumns && this.options.fixedNumber) {
+      this.$fixedBody.off('mousewheel').on('mousewheel', e => {
+        const deltaY = e.originalEvent.wheelDeltaY
+        const top = this.$tableBody.scrollTop() - deltaY
+        const fixedBody = this.$fixedBody[0]
+
+        if (
+          deltaY > 0 && top > 0 ||
+          deltaY < 0 && top < fixedBody.scrollHeight - fixedBody.clientHeight
+        ) {
+          e.preventDefault()
+        }
+        this.$fixedBody.scrollTop(top)
+        this.$tableBody.scrollTop(top)
+        if (this.options.fixedRightNumber) {
+          this.$fixedBodyRight.scrollTop(top)
+        }
+      }).find('tr').hover(e => {
+        const index = $(e.currentTarget).data('index')
+        $(e.currentTarget).addClass('hover')
+
+        this.$tableBody.find(`tr[data-index="${index}"]`).addClass('hover')
+        if (this.options.fixedRightNumber) {
+          this.$fixedBodyRight.find(`tr[data-index="${index}"]`).addClass('hover')
+        }
+      }, e => {
+        const index = $(e.currentTarget).data('index')
+        $(e.currentTarget).removeClass('hover')
+
+        this.$tableBody.find(`tr[data-index="${index}"]`).removeClass('hover')
+        if (this.options.fixedRightNumber) {
+          this.$fixedBodyRight.find(`tr[data-index="${index}"]`).removeClass('hover')
+        }
+      })
+    }
+
+    if (this.needFixedColumns && this.options.fixedRightNumber) {
+      this.$fixedBodyRight.off('mousewheel').on('mousewheel', e => {
+        const deltaY = e.originalEvent.wheelDeltaY
+        const top = this.$tableBody.scrollTop() - deltaY
+        const fixedBody = this.$fixedBodyRight[0]
+
+        if (
+          deltaY > 0 && top > 0 ||
+          deltaY < 0 && top < fixedBody.scrollHeight - fixedBody.clientHeight
+        ) {
+          e.preventDefault()
+        }
+        this.$fixedBodyRight.scrollTop(top)
+        this.$tableBody.scrollTop(top)
+        if (this.options.fixedNumber) {
+          this.$fixedBody.scrollTop(top)
+        }
+      }).find('tr').hover(e => {
+        const index = $(e.currentTarget).data('index')
+        $(e.currentTarget).addClass('hover')
+
+        this.$tableBody.find(`tr[data-index="${index}"]`).addClass('hover')
+        if (this.options.fixedNumber) {
+          this.$fixedBody.find(`tr[data-index="${index}"]`).addClass('hover')
+        }
+      }, e => {
+        const index = $(e.currentTarget).data('index')
+        $(e.currentTarget).removeClass('hover')
+
+        this.$tableBody.find(`tr[data-index="${index}"]`).removeClass('hover')
+        if (this.options.fixedNumber) {
+          this.$fixedBody.find(`tr[data-index="${index}"]`).removeClass('hover')
+        }
+      })
+    }
   }
   }
 }
 }

+ 20 - 17
src/extensions/fixed-columns/bootstrap-table-fixed-columns.scss

@@ -1,27 +1,30 @@
-.fixed-table-header-columns,
-.fixed-table-body-columns {
+@import '../../themes/bootstrap/variables.scss';
+
+.bootstrap-table {
+  tr.hover {
+    background: $hover-bg;
+  }
+}
+
+.fixed-columns,
+.fixed-columns-right {
   position: absolute;
   position: absolute;
+  top: 0;
+  height: 100%;
   background-color: #fff;
   background-color: #fff;
   box-sizing: border-box;
   box-sizing: border-box;
-  overflow: hidden;
   z-index: 1;
   z-index: 1;
-}
 
 
-.fixed-table-header-columns {
-  z-index: 2;
+  .fixed-table-body {
+    overflow: hidden!important;
+    animation: none;
+  }
 }
 }
 
 
-.fixed-table-header-columns .table,
-.fixed-table-body-columns .table {
-  border-right: 1px solid #ddd;
+.fixed-columns {
+  left: 0;
 }
 }
 
 
-.fixed-table-header-columns .table.table-no-bordered,
-.fixed-table-body-columns .table.table-no-bordered {
-  border-right: 1px solid transparent;
-}
-
-.fixed-table-body-columns table {
-  position: absolute;
-  animation: none;
+.fixed-columns-right {
+  right: 0;
 }
 }