阅读 554
微信小程序 自定义table(固定左侧栏和顶部栏)

微信小程序 自定义table(固定左侧栏和顶部栏)

需求背景

公司面向B端的用户需要看大量报表,但是在滚动的时候经常看不到数据对比,看着看着就不知道对应的数据是啥含义了,如是领导让我弄一个固定表头和前面两行的效果。想到小程序没有table组件就只能自己手撸一个组件咯,本篇文章就基于这样的场景诞生了!

需求设计

原有功能点

1.固定顶部标题栏
2.固定左侧某几列
复制代码

延伸功能点

1.标题栏配置
2.固定栏的数量配置
3.格子高度
4.格子宽度
5.组件高度
复制代码

功能实现

功能的核心点是:利用position:sticky这个粘性属性来实现,避免获取dom用js来算位置进行定位。
复制代码

position:sticky相关知识点点这里

dom结构

<!-- max-height:最大高度;--hegiht: 格子高度-->
<view class="table" style="max-height:{{height}}px;--height:{{cellHeight+'rpx'}}">
  <view class="content-list" style="width:{{normalWidth+fixedWidth}}rpx">
    <view class="left-box">
    <!-- 左侧固定部分 -->
    <!-- 左侧固定区域标题栏 -->
      <view 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:for="{{fixedData}}" 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">
    <!-- 右侧非固定部分 -->
      <view 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-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>
复制代码

样式

/* 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;
}
复制代码

js

// compoent/table/index.js
/**
 * 
 */
Component({
  /**
   * 组件的属性列表
   */
  properties: {
    /**
     * 组件高度 默认500 单位px
     */
    height:{ 
      type:Number,
      value:500
    },
    /**
     * 表头配置
     */
    columns:{
      type:Array,
      value:[]
    },
    source:{ // 源数据
      type:Array,
      value:[]
    },
    fixedCount:{ // 定在左侧默认的数量
      type:Number,
      value:1
    },
    cellHeight:{ // 格子高度 默认80  单位rpx
      type:Number,
      value:80
    },
    cellWidth:{ // 格子宽度 默认150 单位 rpx
      type:Number,
      value:150
    }

  },

  /**
   * 组件的初始数据
   */
  data: {
    columns:[
      {
        name:'口碑', //标题名称
        key:'shopName' //对应的数据‘key’
      },
    ], // 标题栏配置
    normalKey:[], // 非固定标题的key
    normalData:[], // 非固定标题的数据
    fixedData:[], //固定标题的数据
    fixedKey:[],//需要固定在左侧的参数key
    fixedWidth:0, //固定标题区域的宽度
    normalWidth:0,//非固定区域的宽度
  },
  lifetimes:{
    attached:function(){
      let {source} = this.data
      this._updateData(source)
    }
  },
  observers:{
    // 监听 源数据的变
    'source':function(source){
      // 更新table数据
      this._updateData(source)
      console.log(this.data);
    }
  },


  /**
   * 组件的方法列表
   */
  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
      })
    }
  }
})

复制代码

效果图

无图无真相,实际效果如下图:

1625449785550939.gif

文章分类
前端