微信小程序table表格自定义组件实现

效果

    1. 左图是多列并且给了最大高度的效果。
    2. 右图是没有给某列固定宽度并且四列的宽度加起来不超出屏幕宽度的效果。
    3. 在不为某列设置固定宽度的情况下,四列及四列以下均是平分屏幕宽度的,并且不能左右滑动。
微信小程序table表格自定义组件实现_第1张图片微信小程序table表格自定义组件实现_第2张图片

属性

属性 类型 默认值 必填 说明
tabData Array [ ] 数据源
columns Array [ ] 数据列
setting Object { } 自定义样式配置项

columns

属性 类型 默认值 必填 说明
label String 表格标题
prop Array 表格中需要展示的数据列
onclick Boolean false 为某一列设置点击事件,若同时为多列设置了点击事件,则只有第一个生效
fontSize Number 24 某一列的字体大小,单位:rpx
fontWeight Number / String normal 某一列的字重(粗细),支持 css 的所有属性值
textDecoration String none 某一列的文本修饰,支持 css 的所有属性值
color String 某一列的字体颜色,支持十六进制、RGB、RGBA、英文单词

setting

属性 类型 默认值 必填 说明
tableOutBorder String 表格外边框,支持三值写法,例如:2rpx solid #ebeef5
tableInBorder String 表格内边框,支持三值写法,例如:2rpx solid #ebeef5
tableInBorderLevel Boolean false 表格内是否只显示水平边框
tableRadius String 表格圆角
theadHeight String 表格标题的高度
theadAlign String left 表格标题的字体对齐方式,值:left、center、right
theadColor String 表格标题的字体颜色,支持十六进制、英文单词
theadBgColor String 表格标题的背景颜色,支持十六进制、RGB、RGBA、英文单词
theadFontSize Number 24 表格标题的字体大小,单位:rpx
theadFontWeight Number / String bold 表格标题的字重(粗细),支持 css 的所有属性值
tbodyHeight String 表格体的高度, 用于垂直滚动
tbodyAlign String left 表格体的字体对齐方式,值:left、center、right
tbodyColor String 表格体的的字体颜色,支持十六进制、英文单词
tbodyBgColor String 表格体的背景颜色,支持十六进制、RGB、RGBA、英文单词
tbodyFontSize Number 24 表格体的字体大小,单位:rpx
tbodyFontWeight Number / String normal 表格体的字重(粗细),支持 css 的所有属性值
trHeight String 表格体的行的高度
stripe String 表格体的斑马纹背景色,支持十六进制、RGB、RGBA、英文单词

子组件WXML

<wxs src="./index.wxs" module="filter" />
<view class="container">
  <view class="table"
        style="width:{{headWidth}};border-radius: {{config.tableRadius}}rpx;border:{{config.tableOutBorder}};border-bottom:{{config.tableOutBorder=='none'?(!!config.tableInBorder?config.tableInBorder:'2rpx solid #ebeef5'):''}};">
    <view class="thead" style="min-height:{{config.theadHeight}}rpx;background:{{config.theadBgColor}};">
      <view class="th"
            wx:for="{{column}}"
            wx:key="index"
            style="flex-grow:0;flex-basis:{{headWidth=='100%'?(100/column.length)+'%':item.width+'rpx'}};color:{{config.theadColor}};font-size:{{config.theadFontSize}}rpx;font-weight:{{config.theadFontWeight}};border-right:{{index==(column.length - 1)?'none':(config.tableInBorderLevel?'none':config.tableInBorder)}};border-bottom:{{config.tableInBorder}};">
        <view class="txt" style="text-align:{{config.theadAlign}};">{{item.label}}view>
      view>
    view>
    <scroll-view scroll-y wx:if="{{tabData.length > 0}}" style="max-height:{{config.tbodyHeight}}rpx;">
      <view class="tr"
            wx:for="{{tabData}}"
            wx:for-item="item"
            wx:key="index"
            style="min-height:{{config.trHeight}}rpx;background:{{config.tbodyBgColor}};">
        <view class="td"
              wx:for="{{column}}"
              wx:for-item="col"
              wx:for-index="colIndex"
              wx:key="colIndex"
              style="flex-grow:0;flex-basis:{{headWidth=='100%'?(100/column.length)+'%':col.width+'rpx'}};background:{{index%2!=0?config.stripe:''}};color:{{config.tbodyColor}};font-size:{{config.tbodyFontSize}}rpx;font-weight:{{config.tbodyFontWeight}};border-right:{{colIndex==(column.length - 1)?'none':(config.tableInBorderLevel?'none':config.tableInBorder)}};border-bottom:{{index==tabData.length-1?'none':config.tableInBorder}};">
          <view class="txt"
          		data-value="{{item}}"
                bindtap="{{(col.οnclick==true||col.οnclick=='true')?'btnAction':''}}"
          		style="text-align:{{config.tbodyAlign}};font-size:{{col.fontSize}}rpx;font-weight:{{col.fontWeight}};text-decoration:{{col.textDecoration}};color:{{col.color}};">
            <block wx:if="{{!!col.type}}">{{filter[col.type](item[col.prop], col.param)}}block>
            <block wx:else>{{item[col.prop]}}block>
          view>
        view>
      view>
    scroll-view>
    <view wx:if="{{tabData.length === 0}}" class="msg">
      <view>暂无数据~view>
    view>
  view>
view>

子组件JS

Component({
  data: {
    headWidth: null, // 设置表格的整体宽度,用于水平滚动
    column: [], // 表头标题
    config: { // 表格自定义样式设置
      tableOutBorder: '', // 表格的表框
      tableInBorder: '', // 表格的表框
      tableInBorderLevel: false, // 表格内只显示水平边框
      tableRadius: '', // 表格圆角
      theadHeight: '', // 表头的高度
      theadAlign: '', // 表头的字体对齐
      theadColor: '', // 表头的字体颜色
      theadBgColor: '', // 表头的背景色
      theadFontSize: '', // 表头的字体大小
      theadFontWeight: '', // 表头的字体粗细
      tbodyHeight: '', // 表格 tbody 的高度, 用于垂直滚动
      tbodyAlign: '', // 表格行的字体对齐方式
      tbodyColor: '', // 表格行的字体颜色
      tbodyBgColor: '', // 表格行的背景色
      tbodyFontSize: '', // 表格行的字体大小
      tbodyFontWeight: '', // 表格行的字体粗细
      trHeight: '', // 表格行 tr 的高度
      stripe: '' // 表格的斑马纹背景色
    }
  },
  properties: {
    tabData: { // 父组件传入的表格数据
      type: Array,
      value: []
    },
    columns: { // 父组件传入的表头标题
      type: Array,
      value: []
    },
    setting: { // 父组件传入的表格自定义样式
      type: Object,
      value: {}
    }
  },
  observers: {
    'tabData'(val) {
      // console.log('tableData', val)
    },
    'columns'(val) {
      if(val.length !== 0) {
        let width = 0
        let num = 0
        val.forEach((item)=>{
          // 判断是否设置了列宽,没有的话赋值默认的宽度 186,单位rpx
          if(!!item.width) {
            width += item.width/1
          } else {
            item.width = 186
            width = width + 186
          }
          // 如果给多列添加了点击事件,则第一个绑定了点击事件的列生效
          if(!!item.onclick && (item.onclick == true || item.onclick == 'true')) {
            num++
            if(num > 1) {
              item.onclick = false
            }
          }
        })
        // 判断table的宽度是否超出屏幕的宽度,超出则赋值固定的宽度,否则赋值百分比
        if(width < 750) {
          width = '100%'
        } else {
          width = width + 'rpx'
        }
        this.setData({
          column: val,
          headWidth: width
        })
      }
    },
    'setting'(val) {
      // 判断传入的表格设置项是否为空
      if (Object.keys(val).length !== 0) {
        for (let key in val) {
          let str = null
          if(key == 'tableInBorderLevel' && (val[key] == true || val[key] == 'true')) {
            str = true
          } else if(key == 'tableInBorderLevel') {
            str = false
          } else {
            str = String(val[key]).replace(/(^\s*)|(\s*$)/g, '')
          }
          if(str != '' && str != null && str != 'null' && str != undefined && str != 'undefined') {
            this.data.config[key] = str
          }
        }
        this.setData({
          config: this.data.config
        })
      }
    }
  },
  methods: {
    // 表格某行的点击事件
    btnAction: function(e) {
      let value = e.currentTarget.dataset.value // value:一个包含点击行所有数据的对象
      this.triggerEvent("getCurrentValue", value)
    }
  }
})

子组件WXS

    内含格式化时间、价格、百分比的方法

// 格式化时间
function time(val, option) {
  var date = getDate(val)
  var year = date.getFullYear()
  var month = date.getMonth() + 1
  var day = date.getDate()
  var week = date.getDay()
  var hour = date.getHours()
  var minute = date.getMinutes()
  var second = date.getSeconds()
  
  //获取 年月日
  if (option == 'YY-MM-DD') return [year, month, day].map(formatNumber).join('-')

  //获取 年月
  if (option == 'YY-MM') return [year, month].map(formatNumber).join('-')

  //获取 年
  if (option == 'YY') return [year].map(formatNumber).toString()

  //获取 月
  if (option == 'MM') return  [mont].map(formatNumber).toString()

  //获取 日
  if (option == 'DD') return [day].map(formatNumber).toString()

  //获取 年月日 周一 至 周日
  if (option == 'YY-MM-DD Week')  return [year, month, day].map(formatNumber).join('-') + ' ' + getWeek(week)

  //获取 月日 周一 至 周日
  if (option == 'MM-DD Week')  return [month, day].map(formatNumber).join('-') + ' ' + getWeek(week)

  //获取 周一 至 周日
  if (option == 'Week')  return getWeek(week)

  //获取 时分秒
  if (option == 'hh-mm-ss') return [hour, minute, second].map(formatNumber).join(':')

  //获取 时分
  if (option == 'hh-mm') return [hour, minute].map(formatNumber).join(':')

  //获取 分秒
  if (option == 'mm-dd') return [minute, second].map(formatNumber).join(':')

  //获取 时
  if (option == 'hh')  return [hour].map(formatNumber).toString()

  //获取 分
  if (option == 'mm')  return [minute].map(formatNumber).toString()

  //获取 秒
  if (option == 'ss') return [second].map(formatNumber).toString()

  //默认 年月日 时分秒 
  return [year, month, day].map(formatNumber).join('-') + ' ' + [hour, minute, second].map(formatNumber).join(':')
}

function formatNumber(n) {
  n = n.toString()
  return n[1] ? n : '0' + n
}

function getWeek(n) {
  switch(n) {
    case 1:
      return '星期一'
    case 2:
      return '星期二'
    case 3:
      return '星期三'
    case 4:
      return '星期四'
    case 5:
      return '星期五'
    case 6:
      return '星期六'
    case 7:
      return '星期日'
  }
}
// 格式化价格
function price(val, option) {
  var option = option || 0
   // 不是数字返回空
   if(val != null && val != '' && isNaN(val/1)) {
    return ''
  }
  if(!!val && val != 'null' && val != 'undefined') {
    return val.toFixed(option)
  }
  return ''
}
// 格式化百分比
function percent(val) {
  // 不是数字返回空
  if(val != null && val != '' && isNaN(val/1)) {
    return ''
  }
  // 如果值小于万分位(小于 0.01%)则返回 0%
  if(val < 0.0001) {
    return '0%'
  }
  // 小数 *100 后不包含小数点,返回 *100 后的结果
  if(val >= 0.0001 && ((val * 100) + '').indexOf('.') == -1) {
    return (val * 100) + '%'
  }
  // 有些小数 *100 之后会出现很长的位数,比如0.07*100=0.000000000001
  // 先处理成数组再截取 arr[1] 的前两个字符判断是否等于0,等于 0 返回 arr[0],不等于 0 则保留两位小数
  if(val >= 0.0001 && ((val * 100) + '').indexOf('.') > -1) {
    if((val * 100 + '').split('.')[1].slice(0,2) == 0){
      return (val * 100 + '').split('.')[0] + '%'
    }
    return (val * 100).toFixed(2) / 1 + '%'
  }
}

module.exports.time = time;
module.exports.price = price;
module.exports.percent = percent;

子组件JSON

{
  "component": true
}

子组件WXSS

.container {
  overflow-x: scroll;
}
.table {
  border: 2rpx solid #ebeef5;
  border-bottom: 2rpx solid #ebeef5;
  border-radius: 0;
  box-sizing: border-box;
  background: #fff;
  font-size: 24rpx;
  color: #606266;
  overflow: hidden;
}
/* 表头 */
.thead {
  display: flex;
}
.th {
  padding: 10rpx 20rpx;
  border-right: 2rpx solid #ebeef5;
  border-bottom: 2rpx solid #ebeef5;
  display: flex;
  align-items: center;
}
.th .txt {
  font-weight: bold;
  text-align: left;
}
.tr {
  display: flex;
}
.td {
  padding: 10rpx 20rpx;
  border-right: 2rpx solid #ebeef5;
  border-bottom: 2rpx solid #ebeef5;
  display: flex;
  align-items: center;
}
.td .txt {
  text-align: left;
  font-weight: normal;
}
.msg {
  width: 750rpx;
  height: 240rpx;
  line-height: 240rpx;
  font-size: 26rpx;
  text-align: center;
}
/* 隐藏表格滚动条 */
::-webkit-scrollbar {
  width: 0;
  height: 0;
  color: transparent;
}

父组件WXML

<view class="container">
  <view class="table">
    <table tabData="{{tabData}}"
    	   columns="{{columns}}"
    	   setting="{{setting}}"
    	   bind:getCurrentValue="getCurrentValue">
     table>
  view>
view>

父组件JS

Page({
  data: {
    // 表格数据
    tabData: [
      { 
        id: 1,
        name: '上官婉儿',
        location: '法师 / 刺客',
        specialty: '爆发 / 突进',
        skill: '笔阵 / 篆法·疾势 / 飞白·藏锋 / 章草·横鳞',
        price: 13888,
        showUpRate: 0.001,
        shelveTime: 1545062400000
      },
      {
        id: 2,
        name: '王昭君',
        location: '法师',
        specialty: '控制 / 冰冻',
        skill: '冰封之心 / 凋零冰晶 / 禁锢寒霜 / 凛冬已至',
        price: 8888,
        showUpRate: 0.01,
        shelveTime: 1445270400000
      },
      { 
        id: 3,
        name: '老夫子',
        location: '战士',
        specialty: '突进',
        skill: '师道尊严 / 圣人训诫 / 举一反三 / 圣人之威',
        price: 8888,
        showUpRate: 0.0003,
        shelveTime: 1445270400000
      },
      { 
        id: 4,
        name: '狄仁杰',
        location: '射手',
        specialty: '',
        skill: '迅捷 / 六令追凶 / 逃脱 / 王朝密令',
        price: 8888,
        showUpRate: 0.06,
        shelveTime: 1445270400000
      },
      { 
        id: 5,
        name: '墨子',
        location: '法师 / 战士',
        specialty: '控制 / 护盾',
        skill: '兼爱非攻 / 和平漫步 / 机关重炮  /墨守成规',
        price: 8888,
        showUpRate: 0.005,
        shelveTime: 1445270400000
      },
      { 
        id: 6,
        name: '盘古',
        location: '战士',
        specialty: '突进 / 收割',
        skill: '盘古斧 / 狂怒突袭 / 压制之握 / 开天辟地 / 聚合为一',
        price: 13888,
        showUpRate: 0.00001,
        shelveTime: 1550764800000
      },
      { 
        id: 7,
        name: '猪八戒',
        location: '坦克',
        specialty: '团控 / 回复',
        skill: '毫发无伤 / 肉弹蹦床 / 倒打一耙 / 圈养时刻',
        price: 13888,
        showUpRate: 0.4,
        shelveTime: 1548777600000
      },
      { 
        id: 8,
        name: '伽罗',
        location: '射手',
        specialty: '远程消耗 / 团队',
        skill: '破魔之箭 / 渡灵之箭 / 静默之箭 / 纯净之域',
        price: 13888,
        showUpRate: 0.8,
        shelveTime: 1537977600000
      },
      {
        id: 9,
        name: '李信',
        location: '战士',
        specialty: '突进 / 团控',
        skill: '灰暗利刃 / 急速突进 / 强力斩击 / 力量觉醒·光 / 力量觉醒·暗',
        price: 13888,
        showUpRate: 0.07,
        shelveTime: 1542816000000
      },
      { 
        id: 10,
        name: '云中君',
        location: '刺客 / 战士',
        specialty: '突进 / 收割',
        skill: '云间游 / 天隙鸣 / 若英·华彩 / 风雷引',
        price: 13888,
        showUpRate: 0.006,
        shelveTime: 1557504000000
      },
      { 
        id: 11,
        name: '瑶',
        location: '辅助',
        specialty: '团队增益',
        skill: '山鬼·白鹿 / 若有人兮 / 风飒木萧 / 独立兮山之上',
        price: 13888,
        showUpRate: 0.9,
        shelveTime: 1555344000000
      },
      {
        id: 12,
        name: '米莱狄',
        location: '法师',
        specialty: '持续输出 / 推进',
        skill: '机械仆从 / 空中力量 / 强制入侵 / 浩劫磁场',
        price: 13888,
        showUpRate: 0.8,
        shelveTime: 1526313600000
      },
      { 
        id: 13,
        name: '狂铁',
        location: '战士',
        specialty: '突进 / 团控',
        skill: '无畏战车 / 碎裂之刃 / 强袭风暴 / 力场压制',
        price: 13888,
        showUpRate: 0.09,
        shelveTime: 1524153600000
      },
      { 
        id: 14,
        name: '斐擒虎',
        location: '刺客 / 战士',
        specialty: '远程消耗 / 收割',
        skill: '寸劲 / 冲拳式 / 气守式 / 虎啸风生',
        price: 13888,
        showUpRate: 0.007,
        shelveTime: 1519747200000
      },
      { 
        id: 15,
        name: '明世隐',
        location: '辅助',
        specialty: '团队增益',
        skill: '大吉大利 / 临卦·无忧 / 师卦·飞翼 / 泰卦·长生',
        price: 13888,
        showUpRate: 0.06,
        shelveTime: 1513094400000
      }
    ],
    // 表格标题列
    columns: [
      { label: '英雄名称', prop: 'name', onclick: true, fontSize: '',fontWeight: 600, textDecoration: 'underline', color: '#000'},
      { label: '英雄定位', prop: 'location'},
      { label: '英雄特长', prop: 'specialty'},
      { label: '英雄技能', prop: 'skill', width: 700, fontSize: '', fontWeight: 400, textDecoration: '', color: ''},
      { label: '英雄价格', prop: 'price', type: 'price'},
      { label: '出场率', prop: 'showUpRate', type: 'percent'},
      { label: '上架时间', prop: 'shelveTime', type: 'time', param: 'YY-MM-DD'}
    ],
    // 自定义样式配置项
    setting: {
      tableRadius: 0, // 表格圆角
      tableOutBorder: '', // 表格外边框
      tableInBorder: '', // 表格内边框
      tableInBorderLevel: 'true', // 表格内只显示水平边框
      theadHeight: 70, // 表头的高度
      theadAlign: '', // 表头的字体对齐方式
      theadColor: '', // 表头的字体颜色
      theadBgColor: '', // 表头的背景色
      theadFontSize: '', // 表头的字体大小
      theadFontWeight: '', // 表头的字体粗细
      tbodyHeight: '600',  // 表格 tbody 的高度, 用于垂直滚动
      tbodyAlign: '', // 表格行的的字体对齐方式
      tbodyColor: '', // 表格行的字体颜色
      tbodyBgColor: '', // 表格行的背景色
      tbodyFontSize: '', // 表格行的字体大小
      tbodyFontWeight: '', // 表格行的字体粗细
      trHeight: 70, // 表格行 tr 的高度
      stripe: '#fdf5e6' // #fafafa #f5f5f5 #fdf5e6 #fff8dc #f0f9eb
    }
  },
  /**
   * 生命周期函数--监听页面加载
   */
  onLoad: function (options) {

  },
  /**
   * 生命周期函数--监听页面显示
   */
  onShow: function () {
    
  },
  // 表格的自定义点击事件
  getCurrentValue(e) {
    const { name } = e.detail
    wx.showToast({
      title: name,
      icon: 'none',
      duration: 1500
    })
  }
})

父组件JSON

{
  "navigationBarTitleText": "搜索",
  "usingComponents": {
    "table": "../../components/table/index"
  }
}

父组件WXSS

page {
  background: #fff;
}
.container {
  width: 100%;
}
.table {
  width: 100%;
  margin: 0 auto 30rpx;
}

你可能感兴趣的:(微信小程序,微信小程序,小程序,table,表格,自定义组件)