Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

WeChat Mini Program Native Table Component: Fixed Header, Adaptive Column Width, Cell Click Support and Zebra Striping

Tech May 10 4

FixedHeaderScrollTable

A native WeChat Mini Program table component built with fixed sticky headers, automatic adaptive column widths, cell-level click event callbacks, and alternating zebra stripe row styling.

Update Log

2024-06-06:

  1. Fixed layout conflict bug that prevented the table from rendering normally alongside other UI components on a single page.

Core Features

  • Fixed sticky header: The header bar remains pinned to the top of the viewport during vertical scrolling, giving users constant column context when browsing large datasets.
  • Cell-level click callback: Triggers a custom event when any non-header cell is tapped, pasing corresponding row and column indices for targeted business logic execution.
  • Dual-axis scroll support: Table content supports both horizontal and vertical scrolling to fit datasets with large numbers of columns or rows.
  • Adaptive column width: Minimum column width is automatically calculated based on the longest header text, ensuring consistent alignment between header and data cells.
  • Zebra stripe styling: Alternating row background colors are applied by default to improve data readability for long tables.
  • Customizable configurations: Supports custom header background colors and placeholder text for empty cells.

Component Properties

Property Type Default Required Description
column-titles Array [] Yes Array of header column display names
dataset Array [] Yes Two-dimensional array of table row data
bind:cellclick eventhandle - Yes Callback triggered on non-header cell tap. e.detail.row returns the row index, e.detail.col returns the column index of the tapped cell
enable-zebra-stripe Boolean true No Toggle zebra stripe alternating row backgrounds
enable-cell-border Boolean false No Toggle cell border display
header-bg-color String #2d66cf No Custom header background color
empty-cell-placeholder String N/A No Placeholder text displayed for empty cells

Component Source Code

1. FixedHeaderScrollTable.js

// components/FixedHeaderScrollTable/FixedHeaderScrollTable.js
Component({
  properties: {
    columnTitles: {
      type: Array,
      value: []
    },
    dataset: {
      type: Array,
      value: []
    },
    emptyCellPlaceholder: {
      type: String,
      value: 'N/A'
    },
    enableZebraStripe: {
      type: Boolean,
      value: true
    },
    enableCellBorder: {
      type: Boolean,
      value: false
    },
    headerBgColor: {
      type: String,
      value: '#2d66cf'
    }
  },

  data: {
    minColWidth: 75,
    headerBarHeight: 2.8,
    headerScrollOffset: 0
  },

  methods: {
    calculateMinColWidth: function (colTitles) {
      const horizontalPadding = 10;
      const perCharWidth = 14;
      const maxTitleLength = colTitles.reduce((maxLen, currentTitle) => {
        return Math.max(maxLen, currentTitle.length)
      }, 0);
      return horizontalPadding + perCharWidth * maxTitleLength;
    },

    syncHeaderScroll: function (e) {
      const currentScrollOffset = e.detail.scrollLeft;
      this.setData({
        headerScrollOffset: currentScrollOffset
      });
    },

    handleCellTap: function (e) {
      this.triggerEvent('cellclick', e.currentTarget.dataset);
    }
  },

  ready: function () {
    const computedMinWidth = this.calculateMinColWidth(this.data.columnTitles);
    this.setData({
      minColWidth: computedMinWidth
    });
  }
})

2. FixedHeaderScrollTable.json

{
  "component": true,
  "styleIsolation": "apply-shared",
  "usingComponents": {}
}

3. FixedHeaderScrollTable.wxml

<!--components/FixedHeaderScrollTable/FixedHeaderScrollTable.wxml-->
<scroll-view 
  class="header-wrapper" 
  scroll-x="true" 
  scroll-left="{{headerScrollOffset}}"
  style="pointer-events: none; position: sticky; top: 0; z-index: 99;"
>
  <view class="table-row">
    <view 
      class="header-cell" 
      style="min-width: {{minColWidth}}px; {{enableCellBorder ? 'border: 0.1px solid #333;' : ''}} background: {{headerBgColor}}"
      wx:for="{{columnTitles}}"
      wx:key="*this"
      wx:for-item="title"
    >
      <text>{{title}}</text>
    </view>
  </view>
</scroll-view>

<scroll-view 
  class="table-content" 
  wx:if="{{columnTitles.length > 0}}"
  scroll-x="true"
  bindscroll="syncHeaderScroll"
  style="padding-top: {{headerBarHeight}}rem;"
>
  <view 
    class="table-row {{enableZebraStripe ? 'zebra-row' : ''}}"
    wx:for="{{dataset}}"
    wx:key="*this"
    wx:for-index="rowIdx"
    wx:for-item="rowData"
  >
    <view 
      class="data-cell"
      style="min-width: {{minColWidth}}px; {{enableCellBorder ? 'border: 0.1px solid #333;' : ''}} {{enableZebraStripe && rowIdx % 2 === 1 ? 'background: #f5f5f5;' : ''}}"
      wx:for="{{rowData}}"
      wx:key="*this"
      wx:for-item="cellData"
      wx:for-index="colIdx"
      bindtap="handleCellTap"
      data-row="{{rowIdx}}"
      data-col="{{colIdx}}"
    >
      {{cellData.length === 0 ? emptyCellPlaceholder : cellData}}
    </view>
  </view>
</scroll-view>

4. FixedHeaderScrollTable.wxss

/* components/FixedHeaderScrollTable/FixedHeaderScrollTable.wxss */
.table-row {
  display: flex;
  align-items: center;
  height: 2.8rem;
  width: 100%;
}

.header-cell, .data-cell {
  display: flex;
  justify-content: center;
  align-items: center;
  padding: 0 12px;
  height: 100%;
}

.header-cell {
  color: #ffffff;
  font-size: 14px;
  font-weight: 500;
}

.zebra-row {
  background: #ffffff;
}
.zebra-row:nth-child(2n) {
  background: #f5f5f5;
}

.data-cell {
  font-size: 13px;
  color: #333333;
}

Usage Example

Place all 4 source files in a folder named FixedHeaderScrollTable under your project component directory, then register the component in the page configuration file.

page.json

{
  "usingComponents": {
    "fixed-header-table": "./components/FixedHeaderScrollTable"
  }
}

page.wxml

<fixed-header-table
  column-titles="{{columnList}}"
  dataset="{{tableData}}"
  bind:cellclick="handleTableCellClick"
  enable-zebra-stripe="{{useZebraStyle}}"
  enable-cell-border="{{showCellBorder}}"
  header-bg-color="{{customHeaderColor}}"
  empty-cell-placeholder="--"
/>

page.js

Page({
  data: {
    useZebraStyle: true,
    showCellBorder: false,
    customHeaderColor: '#2d66cf',
    columnList: ['Product ID', 'Product Name', 'Stock Count', 'Unit Price'],
    tableData: [
      ['1001', 'Wireless Headphone', '246', '$89.9'],
      ['1002', 'Portable Charger', '120', '$29.9'],
      ['1003', 'Bluetooth Speaker', '87', '$45.9'],
      ['1004', 'Smart Watch', '53', '$159.9'],
      ['1005', 'Phone Case', '312', '$12.9'],
      ['1006', 'Screen Protector', '420', '$8.9'],
      ['1007', 'Laptop Stand', '76', '$24.9'],
      ['1008', 'Mechanical Keyboard', '49', '$79.9'],
      ['1009', 'Gaming Mouse', '68', '$39.9'],
      ['1010', 'Webcam', '32', '$59.9'],
      ['1011', 'USB-C Cable', '520', '$6.9'],
      ['1012', 'Wireless Charger', '94', '$32.9'],
      ['1013', 'Tablet Case', '41', '$19.9'],
      ['1014', 'Earbud Tips', '290', '$4.9']
    ]
  },

  handleTableCellClick: function (e) {
    console.log('Tapped cell row index:', e.detail.row, ' | column index:', e.detail.col);
  }
})

Notes

  • This component only supports native WeChat Mini Program environments, no cross-platform compatibility is guaranteed.
  • Multi-level nested headers are not supported in the current version.
  • No default header tap event handler is provided out of the box.

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.