Dynamic switching and anti-shake of element-ui table border

need

The requirement is this:

  1. The previous requirement required the table to be in accordance with the UI design diagram, and the table had no borders.
  2. The new demand requires that those that can support the column width of the table can support dragging.

According to the official website, the border attribute of the table component can display the border when it is set to true. With the border to drag.

But the border is displayed, which is contrary to the previous requirement. At the same time, since the display border is supported by the attribute border, then dynamically updating the value of the border should be able to realize the dynamic switching of the display table border.

Based on this idea, a more compromise approach is adopted:

  1. Borders are not displayed by default
  2. When the mouse moves to the header of the table, the border is displayed, and dragging is allowed at this time.

When the mouse moves, the value of the border attribute is dynamically updated by monitoring the mouse event, and then the display of the border is dynamically switched.

Implementation process

  1. Add a showBorder to the data attribute in the Vue component, the default value is false, and bind it to the border attribute of the table component
<el-table
    :data="tableData"
    :border="showBorder"
    @selection-change="handleSelectionChange"
  >
  ...
export default {
    
    
  data () {
    
    
    return {
    
    
      showBorder: false
    }
  }
}
...
  1. Add mouse events, update the value of showBorder
  ...
  methods: {
    
    
    // 要在表格渲染出来后再加
    addListener () {
    
    
      const tabHeader = this.$el.querySelector('.el-table__header-wrapper')
      if (tabHeader) {
    
    
        tabHeader.onmouseenter = this.updataTableBorder.bind(this, true)
        tabHeader.onmouseleave= this.updataTableBorder.bind(this, false)
      }
    },
    updataTableBorder (value) {
    
    
      this.showBorder = value
    }
  }

  ...

So far, the function has been realized. When the mouse moves to the table header, the border is displayed, and then the column can be dragged. Move the mouse away from the table header to switch to the borderless state.

  • But

If you just do this, you will find that the table will shake when switching. The experience is very bad.
insert image description here

Fix jitter

Cause of jitter

The reason for the jitter is that when the border is not displayed, the width value of the boder is 0. When switching to display the border, the border has the actual width, which will occupy the position, resulting in a position offset when the table is relatively borderless.

How to make the border switch without shaking?

Solution:
first add a border to the table,

  • When the border is not displayed, set the color of the border to transparent and retain its original pixel occupation.
  • When the border is displayed, you only need to update the color value back, and that's it.

Implementation process to solve jitter

Comparing the table styles before and after switching, it is found that the border style involves the following three places.

  1. The outermost div of the table controls the outermost border of the table, and the corresponding border border-top, border-left
  2. Header cell, control the border of the header cell, control the border-bottom, border-right of the header cell
  3. Row cells, control the border of the cell, control the border-bottom, border-right of the row cell

In addition, the table component of element-ui has three attributes, which can just control the style of the table, header cells and all cells. respectively

  • style
  • header-cell-style
  • cell-style

The cell-style attribute configures the style of all cells (including the header), and the header-cell-style only controls the cell style of the header. If you don't configure header-cell-style additionally, you can use cell-style to control the borders of all cells.

Then, to the style, header-cell-style, and cell-style attributes, bind three variables such as tableStyle, headerCellStyle, and cellStyle respectively, and dynamically update these three values. According to the responsive principle of Vue, the corresponding style, header- The cell-style and cell-style attribute values ​​will change accordingly.

<el-table
    :data="tableData"
    :border="showBorder"
    :style="tableStyle"
    :header-cell-style="headerCellStyle"
    :cell-style="cellStyle"
    @selection-change="handleSelectionChange"
  >
const noBordertyle = '1px solid transparent'
const borderStyle = '1px solid #EBEEF5'
export default {
    
    
  data () {
    
    
    return {
    
    
      showBorder: false,
      // 表格样式
      tableStyle: {
    
    
        borderTop: noBordertyle,
        borderLeft: noBordertyle
      },
      // 表头样式
      headerCellStyle: {
    
    
        background: 'rgba(42,113,255,0.03)',
        color: '#000000',
        borderBottom: noBordertyle,
        borderRight: noBordertyle
      },
      // 单元格样式
      cellStyle: {
    
    
        borderBottom: noBordertyle,
        borderRight: noBordertyle
      } 
    }
  },
  methods: {
    
    
    // 要在表格渲染出来后再加
    addListener () {
    
    
      const tabHeader = this.$el.querySelector('.el-table__header-wrapper')
      if (tabHeader) {
    
    
        tabHeader.onmouseenter = this.updataTableBorder.bind(this, true)
        tabHeader.onmouseleave= this.updataTableBorder.bind(this, false)
      }
    },
    updataTableBorder (open) {
    
    
      this.showBorder = open
      const border = open ? borderStyle : noBordertyle

      this.tableStyle.borderTop = border
      this.tableStyle.borderLeft = border

      this.headerCellStyle.borderBottom = border
      this.headerCellStyle.borderRight = border

      this.cellStyle.borderBottom = border
      this.cellStyle.borderRight = border
    }
  }
}

This solves the jitter problem when the border is switched.
insert image description here

Reoptimize

Although the problem has been solved, usually in the project, tables are used in many places, and the styles of the tables are generally consistent.
If it is used directly according to the above process, then in each component that uses the form, these codes must be added to process them. It is quite cumbersome to handle and maintain.
It would be much more comfortable if these processing processes can be put in one place and maintained separately.

Think of Vue's mixin mixed in.

  1. Create a new mix-in file, tableMixin.js, or the code above.
  2. In the component that uses the table, import tableMixin and add it in the mix-in option.
import mixin from ''./mixins/tableMixin


export default {
    
    
  ...
  mixins: [mixin]
}

over! ! !

postscript

After the previous processing is completed, the table does not shake anymore. But after careful observation, it is found that the operation column in the last column of the table does not display the left border. Instead, it is only 1 pixel worse and not displayed.
Check the border style of the cell repeatedly, it is normal. That is to say, it should be displayed under normal circumstances, but it is not. Puzzled.
Looking at this problem the next day, I found that the last operation column uses the fixed attribute, which is a fixed column . That is, when dragging with the horizontal scroll bar, the position of the last operation column remains unchanged.

fixed column

Check the fixed column carefully, check the DOM structure, and find that there is an extra el-table__fixed-right div, the style uses absolute positioning, and the width is set in the inline style. And this node just corresponds to the operation column on the right.

So is this div covering the border element that should be displayed? Because I modified the border by unconventional means, the width value of this absolutely positioned element is no longer accurate, and the border is covered.

Manually adjust the column width of the fixed column to remove 1 pixel. Sure enough, the border appeared.

Now that the crux of the problem is found, it is easy to solve the problem. In the addListener method, it is OK to reduce the width of the div by 1.

    addListener () {
    
    
      const tabHeader = this.$el.querySelector('.el-table__header-wrapper')
      if (tabHeader) {
    
    
        tabHeader.onmouseenter = this.updataTableBorder.bind(this, true)
        tabHeader.onmouseleave= this.updataTableBorder.bind(this, false)
      }

      const fixedRightNode = this.$el.querySelector('.el-table__fixed-right')
      if (fixedRightNode) {
    
    
        const width = fixedRightNode.style.width
        fixedRightNode.style.width = width ? (parseInt(width) - 1) + 'px' : width
      }
    },

Guess you like

Origin blog.csdn.net/u012413551/article/details/123541144