Demand background

The b-end users of the company need to see a large number of reports, but they often can’t see the data comparison when scrolling, so they don’t know what the corresponding data is, so the leader asked me to fix the effect of the table header and the first two lines. Think of a small program without a table component can only hand luk a component, this article is based on such a scene was born!

Demand for design

Original function points

1. Fix the top title bar. 2Copy the code

Extended function points

1. Title bar configuration 2. Number of fixed columns configuration 3. Component heightCopy the code

Function implementation

The core point of the function is: use the sticky attribute of position:sticky to achieve, avoid obtaining DOM and use JS to calculate the position for positioning.Copy the code

Position :sticky Related knowledge dot here

Dom structure

<! -- max-height: maximum height; <view class="table" style="max-height:{{height}}px; --height:{{cellHeight+'rpx'}}"> <view class="content-list" style="width:{{normalWidth+fixedWidth}}rpx"> <view class="left-box"> <! -- Left fixed part --> <! < span style="width:{{fixedWidth}} RPX; display:flex; position:sticky; top:0; "> <view class="header-title" wx:for="{{fixedKey}}" wx:key="index" style="flex-basis:{{item.width}}rpx;" > {{columns[item.index].name}} </view> </view> <! <view wx:key="index" style="width:{{fixedWidth}} RPX; display:flex;" > <view class="header-title" wx:for="{{fixedKey}}" wx:key="keyIndex" wx:for-index="keyIndex" wx:for-item="keyItem" style="flex-basis:{{keyItem.width}}rpx"> {{item[keyItem['key']]}} </view> </view> </view> <view class="right-box"> <! < p style="display:flex; position:sticky; top:0;" > <! <view class="header-title" wx:for="{{normalKey}}" wx:key="index" style="flex-basis:{{item.width}} RPX "> {{columns[item.index].name}} </view> </view> <view class="" style="display:flex; width:{{normalWidth}}rpx;" > <! <view wx:for="{{normalKey}}" wx:key="keyIndex" wx:for-index="keyIndex" wx:for-index="keyIndex" wx:for-item="keyItem" style="display:flex; flex-wrap:wrap; flex-basis:{{keyItem.width}}rpx"> <view class="header-title" wx:for="{{normalData}}" wx:key="index" style="flex-basis:{{keyItem.width}}rpx"> {{item[keyItem['key']]}} </view> </view> </view> </view> </view> </view>Copy the code

style

/* compoent/table/index.wxss */
.table {
  /* width: 100%; */
  overflow-x:auto;
}
.header{
  overflow-x: auto;
  position: sticky;
  display: flex;
}
.header-title {
  height: var(--height);
  box-sizing: border-box;
  font-size: 12px;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  white-space: nowrap;
  background-color: #2E324A;
  color: #fff;
}
.content-list {
  display: flex;
}

.left-box {
  z-index: 9;
  left: 0;
  position: sticky;
}
Copy the code

js

// compoent/table/index.js
/**
 * 
 */
Component({
  /** * Component property list */
  properties: {
    /** * The component height defaults to 500 units px */
    height: {type:Number.value:500
    },
    /** * table header configuration */
    columns: {type:Array.value:[]
    },
    source: {/ / the source data
      type:Array.value:[]
    },
    fixedCount: {// Set the default number on the left
      type:Number.value:1
    },
    cellHeight: {// The grid height defaults to 80 units RPX
      type:Number.value:80
    },
    cellWidth: {// The grid width defaults to 150 RPX
      type:Number.value:150}},/** * The initial data of the component */
  data: {
    columns:[
      {
        name:'word of mouth'.// The title name
        key:'shopName' // The corresponding data 'key'},].// Title bar configuration
    normalKey: [].// Unfixed title key
    normalData: [].// Data without fixed title
    fixedData: [].// Set the title of the data
    fixedKey: [].// The parameter key needs to be fixed on the left
    fixedWidth:0.// Set the width of the header area
    normalWidth:0.// The width of the unfixed area
  },
  lifetimes: {attached:function(){
      let {source} = this.data
      this._updateData(source)
    }
  },
  observers: {// Listen for changes in source data
    'source':function(source){
      // Update table data
      this._updateData(source)
      console.log(this.data); }},/** * list of component methods */
  methods: {
    _updateData(source){
      let {columns,fixedCount,fixedWidth,normalWidth,cellWidth}=this.data
      let [fixedKey,fixedData,normalKey,normalData]=[[],[],[],[]]
      if(columns&& columns.length>0){
        columns.forEach((item,index) = > {
          if(item.fixed && fixedCount>0 && fixedKey.length <= fixedCount){
            fixedKey.push({
              key:item.key,
              index:index,
              width:item.width? item.width:cellWidth }) }else {
            normalKey.push({
              key:item.key,
              index:index,
              width:item.width? item.width:cellWidth }) } }); }if(fixedKey.length>0){
        fixedWidth=0
        source.forEach((item,index) = >{
          let temp={}
          fixedKey.forEach(sonItem= >{
            let tempKey=sonItem.key
            if(sonItem.key=='rank'){
              temp[tempKey]= index+1
            }else{
              temp[tempKey]=item[tempKey]
            }     
          })
          fixedData.push(temp)
        })
        fixedKey.forEach(item= >{
          fixedWidth += item.width
        })
      }
      if(normalKey.length>0){
        normalWidth=0
        source.forEach((item,index) = >{
          let temp={}
          normalKey.forEach(sonItem= >{
            let tempKey=sonItem.key
            if(sonItem=='rank'){
              temp[tempKey]= index+1
            }else{
              temp[tempKey]=item[tempKey]
            }     
          })
          normalData.push(temp)
        })
        normalKey.forEach(item= >{
          normalWidth += item.width
        })
      }
    
      this.setData({
        columns,
        fixedKey,
        normalKey,
        fixedData,
        normalData,
        fixedWidth,
        normalWidth
      })
    }
  }
})

Copy the code

rendering

No picture, no truth, the actual effect is as follows: