微信小程序table表格自定义组件实现
效果属性属性类型默认值必填说明tabDataArray[ ]否数据源columnsArray[ ]是数据列settingObject{ }否自定义样式配置项columns属性类型默认值必填说明labelString是表格标题propArray是表格中需要展示的数据列onclickBooleanfalse否为某一列设置点击事件,若同时为多列设置了点击事件,则只有第一个生效
·
效果
1. 左图是多列并且给了最大高度的效果。
2. 右图是没有给某列固定宽度并且四列的宽度加起来不超出屏幕宽度的效果。
3. 在不为某列设置固定宽度的情况下,四列及四列以下均是平分屏幕宽度的,并且不能左右滑动。
属性
属性 | 类型 | 默认值 | 必填 | 说明 |
---|---|---|---|---|
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;
}
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
已为社区贡献1条内容
所有评论(0)