# tui-virtual-table 虚拟化表格 会员组件 V3.0.0+
介绍
虚拟列表,适用于显示同类的长列表数据类型,对渲染性能有一定的优化效果。
TIP
该组件内部使用了 tui-icon
组件,需同时引入使用,uniapp非easycom模式下需要在组件内手动进行引入。
# 引入
# uni-app引入
第一种,手动引入(可全局引入)
import tuiVirtualTable from "@/components/thorui/tui-virtual-table/tui-virtual-table.vue"
export default {
components:{
tuiVirtualTable
}
}
第二种,开启easycom组件模式,如果不了解如何配置,可先查看 官网文档 (opens new window)。
# uni-app版本平台差异说明
App-Nvue | App-vue | H5 | 微信小程序 | 支付宝小程序 | 百度小程序 | 字节小程序 | QQ小程序 |
---|---|---|---|---|---|---|---|
升级中 | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
# 微信小程序引入(可在app.json中全局引入)
{
"usingComponents": {
"tui-virtual-table": "/components/thorui/tui-virtual-table/tui-virtual-table"
}
}
# 代码演示
部分功能演示,具体可参考示例程序以及文档API。
使用示例
注意:数据文件请根据路径从示例中获取。
<template>
<view class="container">
<view class="tui-page__hd">
<view class="tui-page__title">VirtualTable</view>
<view class="tui-page__desc">虚拟化表格,对长列表数据渲染性能有一定的优化效果。</view>
</view>
<view class="tui-page__bd">
<view class="tui-title" style="padding-top: 0;">基础使用/高度自适应</view>
<view class="tui-table--box">
<tui-virtual-table full :height="0" item-height="0" :table-data="tableData"
:header="headers"></tui-virtual-table>
</view>
<view class="tui-title">通栏/斑马纹/item高度100rpx</view>
<tui-virtual-table full stripe :item-height="100" :height="0" :table-data="tableData"
:header="headers"></tui-virtual-table>
<view class="tui-title">容器高度600rpx,item高度:120rpx,长列表加载</view>
<tui-virtual-table :itemBuffer="50" :item-height="120" ref="virtualList" fixed :header="header"
@click="detail" @scrolltolower="onScrollToLower"></tui-virtual-table>
<view class="tui-title">总高度720rpx,item高度:120rpx,排序(一次性加载时使用)</view>
<tui-virtual-table full outside-header :height="600" :itemBuffer="50" :item-height="120" ref="virtualList2" fixed
:header="header2" @click="detail" @sortChange="sortChange"></tui-virtual-table>
<view class="tui-title">选择框</view>
<tui-virtual-table :height="0" selection full :table-data="tableData" :header="headers"
@selectionChange="change" ref="table"></tui-virtual-table>
</view>
</view>
</template>
<script>
import list from '@/utils/list.js'
let itemCount = 100
const tableData = [{
"id": 1,
"name": "阿拉斯加",
"mobile": "13588889999",
"avatar": "https://thorui.cn/extend/avatar/1.jpg"
},
{
"id": 2,
"name": "阿克苏",
"mobile": "0551-4386721",
"avatar": "https://thorui.cn/extend/avatar/2.jpg"
}, {
"id": 3,
"name": "阿拉善",
"mobile": "4008009100",
"avatar": "https://thorui.cn/extend/avatar/3.jpg"
}, {
"id": 4,
"name": "阿勒泰",
"mobile": "13588889999",
"avatar": "https://thorui.cn/extend/avatar/4.jpg"
}
]
export default {
data() {
return {
disablePullUp: false,
tableData: tableData,
headers: [{
prop: 'id',
label: '编号'
}, {
prop: 'name',
label: '名称'
}, {
prop: 'mobile',
label: '电话'
}],
itemsList: list,
//数据源
items: list,
header: [{
prop: 'id',
label: '编号',
fixed: true,
}, {
prop: 'name',
label: '名称'
}, {
prop: 'mobile',
label: '电话',
width: 280,
}, {
prop: 'avatar',
label: '头像',
width: 200,
imgWidth: 80,
type: 2
}, {
label: '操作',
fixed: 'right',
type: 3,
width: 160,
buttons: [{
text: '查看',
color: '#5677fc',
fontWeight: 600
}]
}],
header2: [{
prop: 'id',
label: '编号',
//是否开启排序
sortable: true,
//排序图标颜色
sortColor: '#5677fc',
//必传:排序数据类型
sortType: 'number'
}, {
prop: 'name',
label: '名称',
sortable: true,
sortColor: '#5677fc',
sortType: 'string'
}, {
prop: 'avatar',
label: '头像',
type: 2
},{
label: '操作',
type: 3,
buttons: [{
text: '查看',
color: '#5677fc',
fontWeight: 600
}]
}]
}
},
onReady() {
this.initData(this.items)
//排序列表,一次行数据渲染
const virtualList2 = this.$refs.virtualList2
virtualList2 && virtualList2.render(this.items, () => {})
},
methods: {
initData(items) {
const startTime = Date.now()
const virtualList = this.$refs.virtualList
virtualList && virtualList.render(items, () => {
const diffTime = Date.now() - startTime
console.log(`success - render time: ${diffTime}ms`)
})
},
loadData(e) {
if (this.items.length >= 1000 || this.disablePullUp) return
this.disablePullUp = true;
uni.showLoading({
title: '正在加载...'
})
setTimeout(() => {
const itemList = list.map(item => {
return {
id: item.id + itemCount,
name: item.name,
avatar: item.avatar,
mobile: item.mobile
}
})
this.items = this.items.concat(itemList)
itemCount += 100
this.initData(this.items)
this.disablePullUp = false;
uni.hideLoading()
}, 500)
console.log('loadData', e)
},
onScrollToLower(e) {
console.log('onScrollToLower', e)
if (e.direction == 'bottom') {
this.loadData(e)
}
},
itemClick(e) {
console.log(e)
},
sortChange(e) {
//排序数据发生改变时触发
console.log(e)
},
detail(e) {
console.log(JSON.stringify(e))
uni.previewImage({
urls: [e.item.avatar]
})
},
change(e) {
console.log(e)
const names = e.map(item => item.name)
this.tui.toast(names.join(',') || '取消选择')
}
}
}
</script>
<style>
.tui-title {
width: 100%;
font-size: 24rpx;
color: #999;
padding: 64rpx 30rpx 30rpx;
box-sizing: border-box;
}
.tui-table--box {
width: 100%;
padding: 0 30rpx;
box-sizing: border-box;
}
</style>
<view class="container">
<view class="tui-page__hd">
<view class="tui-page__title">VirtualTable</view>
<view class="tui-page__desc">虚拟化表格,对长列表数据渲染性能有一定的优化效果。</view>
</view>
<view class="tui-page__bd">
<view class="tui-title" style="padding-top: 0;">基础使用/高度自适应</view>
<view class="tui-table--box">
<tui-virtual-table full height="0" item-height="0" table-data="{{tableData}}" header="{{headers}}"></tui-virtual-table>
</view>
<view class="tui-title">通栏/斑马纹/item高度100rpx</view>
<tui-virtual-table full stripe item-height="{{100}}" height="{{0}}" table-data="{{tableData}}" header="{{headers}}"></tui-virtual-table>
<view class="tui-title">容器高度600rpx,item高度:120rpx,长列表加载</view>
<tui-virtual-table itemBuffer="{{30}}" item-height="{{120}}" id="virtualList" fixed header="{{header}}" bindclick="detail" bindscrolltolower="onScrollToLower"></tui-virtual-table>
<view class="tui-title">容器高度720rpx,item高度:120rpx,排序(一次性加载时使用)</view>
<tui-virtual-table full outsideHeader height="{{600}}" itemBuffer="{{30}}" item-height="{{120}}" id="virtualList2" fixed header="{{header2}}" bindclick="detail" bind:sortChange="sortChange"></tui-virtual-table>
<view class="tui-title">选择框</view>
<tui-virtual-table height="{{0}}" selection full table-data="{{tableData}}" header="{{headers}}" bindselectionChange="change" id="table"></tui-virtual-table>
</view>
</view>
import list from '../../../utils/list.js'
let itemCount = 100;
const tableData = [{
"id": 1,
"name": "阿拉斯加",
"mobile": "13588889999",
"avatar": "https://thorui.cn/extend/avatar/1.jpg"
},
{
"id": 2,
"name": "阿克苏",
"mobile": "0551-4386721",
"avatar": "https://thorui.cn/extend/avatar/2.jpg"
}, {
"id": 3,
"name": "阿拉善",
"mobile": "4008009100",
"avatar": "https://thorui.cn/extend/avatar/3.jpg"
}, {
"id": 4,
"name": "阿勒泰",
"mobile": "13588889999",
"avatar": "https://thorui.cn/extend/avatar/4.jpg"
}
]
let virtualList2, virtualList;
Page({
data: {
disablePullUp: false,
tableData: tableData,
headers: [{
prop: 'id',
label: '编号'
}, {
prop: 'name',
label: '名称'
}, {
prop: 'mobile',
label: '电话'
}],
itemsList: list,
//数据源
items: list,
header: [{
prop: 'id',
label: '编号',
fixed: true
}, {
prop: 'name',
label: '名称'
}, {
prop: 'mobile',
label: '电话',
width: 280,
}, {
prop: 'avatar',
label: '头像',
width: 200,
imgWidth: 80,
type: 2
}, {
label: '操作',
fixed: 'right',
type: 3,
width: 160,
buttons: [{
text: '查看',
color: '#5677fc',
fontWeight: 600
}]
}],
header2: [{
prop: 'id',
label: '编号',
//是否开启排序
sortable: true,
//排序图标颜色
sortColor: '#5677fc',
//必传:排序数据类型
sortType: 'number'
}, {
prop: 'name',
label: '名称',
sortable: true,
sortColor: '#5677fc',
sortType: 'string'
}, {
prop: 'avatar',
label: '头像',
type: 2
},{
label: '操作',
type: 3,
buttons: [{
text: '查看',
color: '#5677fc',
fontWeight: 600
}]
}]
},
onLoad(options) {
},
onReady() {
virtualList = this.selectComponent('#virtualList')
virtualList2 = this.selectComponent('#virtualList2')
this.initData(this.data.items)
//排序列表
virtualList2 && virtualList2.render(this.data.items, () => {})
},
initData(items) {
const startTime = Date.now()
virtualList && virtualList.render(items, () => {
const diffTime = Date.now() - startTime
console.log(`success - render time: ${diffTime}ms`)
})
},
loadData(e) {
if (this.data.items.length >= 1000 || this.data.disablePullUp) return
this.data.disablePullUp = true;
wx.showLoading({
title: '正在加载...'
})
setTimeout(() => {
const itemList = list.map(item => {
return {
id: item.id + itemCount,
name: item.name,
avatar: item.avatar,
mobile: item.mobile
}
})
this.data.items = this.data.items.concat(itemList)
itemCount += 100
this.initData(this.data.items)
this.data.disablePullUp = false;
wx.hideLoading()
}, 500)
console.log('loadData', e)
},
onScrollToLower(e) {
console.log('onScrollToLower', e.detail)
if (e.detail.direction == 'bottom') {
this.loadData(e.detail)
}
},
itemClick(e) {
console.log(e.detail)
},
sortChange(e) {
//排序数据发生改变时触发
console.log(e.detail)
},
detail(e) {
const detail = e.detail
console.log(JSON.stringify(detail))
wx.previewImage({
urls: [detail.item.avatar]
})
},
change(e) {
const data = e.detail;
console.log(data)
const names = data.map(item => item.name)
wx.tui.toast(names.join(',') || '取消选择')
}
})
.tui-title {
width: 100%;
font-size: 24rpx;
color: #999;
padding: 64rpx 30rpx 30rpx;
box-sizing: border-box;
}
.tui-table--box {
width: 100%;
padding: 0 30rpx;
box-sizing: border-box;
}
// Make sure to add code blocks to your code group
# Slots
插槽名称 | 说明 |
---|---|
- | - |
# Props
属性名 | 类型 | 说明 | 默认值 |
---|---|---|---|
height | Number, String | 表格容器高度,传0则为普通表格,不进行长列表优化 | 600 |
unit | String | 表格容器高度单位,可选值:rpx、px | rpx |
background | String | 背景色 | #fff |
itemHeight | Number, String | 表格行(tr)高度 ,单位rpx | 100 |
itemBuffer | Number, String | 可视容器外加载的元素个数,值越大性能越高 | 0 |
upperThreshold | Number, String | 距顶部多远时,触发 scrolltoupper 事件,单位px | 50 |
lowerThreshold | Number, String | 距底部多远时,触发 scrolltolower 事件,单位px | 50 |
enableBackToTop | Boolean | iOS 点击顶部状态栏、安卓双击标题栏时,滚动条返回顶部,只支持竖向 | false |
header | Array | 表头数据,必选参数 | [ ] |
outsideHeader | Boolean | 表头是否放置容器外,仅建议横向数据不超过一屏时使用 | false |
size | Number, String | 表头字体大小,单位rpx | 28 |
color | String | 表头字体颜色 | #333 |
fontWeight | Number, String | 表头字重 | 600 |
headerBgColor | String | 表头背景色 | #fff |
fixed | Boolean | 表头是否固定在顶部,outsideHeader为true时默认固定 | false |
tableData | Array | 表格数据 | [ ] |
full | Boolean | 表格宽度是否铺满剩余空间,仅数据列不超过一屏时使用 | false |
border | Boolean | 是否带有纵向边框 | true |
horBorder | Boolean | 是否带有横向边框 | true |
borderColor | String | 边框颜色 | #eee |
stripe | Boolean | 是否为斑马纹(隔行换色) | false |
stripeColor | String | 斑马纹颜色 | #F8F8F8 |
textSize | Number, String | 表格内容字体大小,单位rpx | 28 |
textColor | String | 表格内容字体颜色 | #333 |
align | String | 单元格对齐方式,可选值:left、center、right | center |
ellipsis | Boolean | 文字超出是否省略,默认换行 | false |
padding | Number, String | 单元格上下padding值,单位rpx | 20 |
selection | Boolean | 是否添加多选框 | false |
initEmitChange | Boolean | 首次加载是否触发 selectionChange 事件 | false |
checkboxColor | String | 选择框选中后颜色 | #5677fc |
checkboxBorderColor | String | 选择框未选中时边框颜色 | #eee |
checkmarkColor | String | 选择框选中时对号颜色 | #fff |
emptyText | String | 表格数据为空时提示文本 | 暂无数据 |
emptySize | String, Number | 表格数据为空时提示文本字体大小,单位rpx | 24 |
emptyColor | String | 表格数据为空时提示文本字体颜色 | #bfbfbf |
londingType | String, Number | 占位类型, 1-显示加载文本 2-显示骨架 | 2 |
loadingText | String | 加载文本内容 | 加载中... |
loadingColor | String | 加载文本字体颜色 | #999 |
isVirtual | Boolean | 是否为虚拟table,设为false时,滚动抖动或出现骨架情况有一定优化 | true |
//header 表头属性详细说明
[{
//表格内容类型:1-text 展示文本 2-image 展示图片 3-button 展示操作按钮,必选
type: 1,
//表头显示名称,可选,内容为空时显示prop
label: '姓名',
//当前列展示数据属性名,结合实际数据传入,必选
prop: 'name',
//单元格宽度,单位rpx
width: 200,
//当前列是否吸顶固定:true-左侧固定,left-左侧固定,right-右侧固定,可选
fixed: true,
//表头字体大小,单位rpx,优先级大于props中size值,可选
size:28,
//表头文字颜色,优先级大于props中color值,可选
color: '',
//单元格字体大小,单位rpx,优先级大于props中textSize值,可选
textSize:28,
//单元格文字颜色,优先级大于props中textColor值,可选
textColor: '',
//图片宽度,单位rpx ,type=2时有效
imgWidth: 80,
//图片高度度,单位rpx ,type=2时有效
imgHeight: 80,
//列单元格对齐方式:left/center/right,优先级大于props中align值,可选
align:'',
//按钮数据,,type=3时有效,可选
buttons: [{
//按钮文本
text: '查看',
//按钮文本颜色
color: '#5677fc',
//按钮字体大小
size: 28,
//按钮字重
fontWeight: 400
}],
//[可选] 是否开启排序
sortable: true,
//[开启排序后则必填] 排序数据类型,可选值:number/date/string
sortType: 'date',
//[可选] 排序图标颜色,不传值则使用默认值
sortColor: '#465CFF',
//[可选] 排序图标right值,默认40(单位rpx),根据列宽度自行调整至合适的位置
sortRight:40,
//[可选] 排序图标大小,单位rpx
sortSize:28
}]
# Events
事件名 | 说明 | 回调参数 |
---|---|---|
change | 数据变化时的回调函数 | { e: 对象数据 } |
scroll | 滚动时触发,使用scroll-view滚动时使用 | { e: 对象数据 } |
scrolltoupper | 滚动到顶部时触发,使用scroll-view滚动时使用 | { e: 对象数据 } |
scrolltolower | 滚动到底部时触发,使用scroll-view滚动时使用 | { e: 对象数据 } |
click | 点击按钮时触发,表头数据type=3时有效 | { index:数据行索引, item:对应数据行数据 btnIndex:按钮索引 } |
trClick | 点击行时触发 | { index:数据行索引, item:对应数据行数据 |
selectionChange | 当选择项发生变化时会触发该事件 | selection:选中数据 |
select | 勾选行 Checkbox 时触发的事件 | { index:数据行索引, item:对应数据行数据, is_selected:是否选中 } |
selectAll | 勾选全选 Checkbox 时触发的事件 | { is_selected:是否全选 } |
sortChange | 排序数据发生改变时触发 | { itemList:排序后列表, virtualItems:虚拟列表,展示的内容数据, sort:排序方式 prop:排序属性字段 } |
# Methods
如何调用方法详见 进阶用法 介绍
方法名 | 说明 | 传入参数 |
---|---|---|
render | 用于动态加载数据,长列表使用时必须调用此方法展示数据 | items, callback |
scrollTo | 滚动到指定的位置 | scrollOffset, callback |
scrollToIndex | 根据索引值滚动到指定的位置 | index, callback |
clearSelection | 用于多选表格,清空用户的选择 | - |
toggleRowSelection | 用于多选表格,切换某一行的选中状态 | row:行数据 selected:是否选中 |
toggleRowDisabled | 用于多选表格,切换某一行的禁用状态 | row:行数据 disabled:是否禁用 |
toggleAllSelection | 用于多选表格,切换所有行的选中状态 | - |
resetSort | 用于有设置排序表格,重置所有排序 | - |
setSort | 用于有设置排序表格,设置排序 | prop:需要排序的字段 sortOrder:排序方式 (ascending/descending) |
//部分方法及参数详细说明
/**
* 更新组件
* @param {Array} items 实际数据列表,当需要动态加载数据时设置
* @param {Function} callback 设置完成后的回调函数
*/
render(items, callback)
/**
* 滚动到指定的位置
* @param {Number} scrollOffset 指定的位置
* @param {Function} callback 设置完成后的回调函数
*/
scrollTo(scrollOffset, callback)
/**
* 根据索引值滚动到指定的位置
* @param {Number} index 指定元素的索引值
* @param {Function} callback 设置完成后的回调函数
*/
scrollToIndex(index, callback)
/**
* 用于多选表格,清空用户的选择
*/
clearSelection()
// ...
# 预览
请以移动端效果为准,touch事件目前尚未在PC端做兼容。
# 特别说明
该组件为 会员组件
,非开源内容,需开通会员才可获取使用。
# 线上程序扫码预览
![]() | ![]() | ![]() |
---|---|---|
ThorUI组件库小程序码 | H5二维码 | ThorUI示例小程序码 |