# tui-virtual-list 虚拟列表 会员组件 V2.9.5+

介绍

虚拟列表,适用于显示同类的长列表数据类型,对渲染性能有一定的优化效果。

TIP

该组件需要与 tui-virtual-item 组件一起使用,需同时引入。

# 引入

# uni-app引入

第一种,手动引入(可全局引入)

import tuiVirtualList from "@/components/thorui/tui-virtual-list/tui-virtual-list.vue"
import tuiVirtualItem from "@/components/thorui/tui-virtual-item/tui-virtual-item.vue"
export default {
	components:{
		tuiVirtualList,
		tuiVirtualItem
	}
}

第二种,开启easycom组件模式,如果不了解如何配置,可先查看 官网文档 (opens new window)

# uni-app版本平台差异说明

App-Nvue App-vue H5 微信小程序 支付宝小程序 百度小程序 字节小程序 QQ小程序
升级中

# 微信小程序引入(可在app.json中全局引入)

{
  "usingComponents": {
    "tui-virtual-list": "/components/thorui/tui-virtual-list/tui-virtual-list",
	"tui-virtual-item": "/components/thorui/tui-virtual-item/tui-virtual-item"
  }
}

# 代码演示

部分功能演示,具体可参考示例程序以及文档API。

scroll-view 局部滚动使用示例

通过 itemBuffer 属性设置可视容器外加载的元素个数,background 属性设置容器背景色。

    <template>
    	<view class="container">
    		<tui-virtual-list :itemBuffer="30" background="#fff" ref="virtualList" @change="onChange"
    			@scrolltolower="onScrollToLower">
    			<tui-virtual-item @click="itemClick(item)" v-for="(item,index) in virtualItems" :key="index">
    				<tui-list-cell padding="0">
    					<view class="tui-list__item">
    						<tui-lazyload-img width="68rpx" height="68rpx" radius="8rpx"
    							:src="item.avatar"></tui-lazyload-img>
    						<view class="tui-name">{{item.id +'-'+ item.name }}</view>
    					</view>
    				</tui-list-cell>
    			</tui-virtual-item>
    		</tui-virtual-list>
    	</view>
    </template>
    
    <script>
        //数据列表可自行定义,示例文件请前往示例项目获取
    	import list from '@/utils/list.js'
    	let itemCount = 100
    	export default {
    		data() {
    			return {
    				startIndex: 0,
    				endIndex: 0,
    				disablePullUp: false,
    				//显示列表
    				virtualItems: [],
    				//数据源
    				items: list
    			}
    		},
    		onReady() {
    			this.updated(this.items)
    		},
    		methods: {
    			updated(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,
    						}
    					})
    					this.items = this.items.concat(itemList)
    					itemCount += 100
    					this.updated(this.items)
    					this.disablePullUp = false;
    					uni.hideLoading()
    				}, 1000)
    				console.log('loadData', e)
    			},
    			onChange(e) {
    				const {
    					startIndex,
    					endIndex,
    					items
    				} = e
    				console.log('onChange', e)
    				if (this.startIndex !== startIndex || this.endIndex !== endIndex) {
    					this.startIndex = startIndex;
    					this.endIndex = endIndex;
    					this.virtualItems = items
    				}
    			},
    			onScrollToLower(e) {
    				this.loadData(e)
    				console.log('onScrollToLower', e)
    			},
    			itemClick(e) {
    				console.log(e)
    			}
    		}
    	}
    </script>
    
    <style>
    	.tui-list__item {
    		width: 100%;
    		height: 100rpx;
    		padding: 16rpx 30rpx;
    		box-sizing: border-box;
    		display: flex;
    		align-items: center;
    	}
    
    	.tui-name {
    		width: 90%;
    		font-size: 32rpx;
    		padding-left: 20rpx;
    		padding-right: 40rpx;
    		box-sizing: border-box;
    		white-space: nowrap;
    		overflow: hidden;
    		text-overflow: ellipsis;
    	}
    </style>
    	
    
     <tui-virtual-list itemBuffer="{{30}}" background="#fff" id="virtualList" bindchange="onChange" bindscrolltolower="onScrollToLower">
      <tui-virtual-item bindclick="itemClick" data-item="{{item}}" wx:for="{{virtualItems}}" wx:key="index">
    	<tui-list-cell padding="0">
    	  <view class="tui-list__item">
    		<tui-lazyload-img width="68rpx" height="68rpx" radius="8rpx" src="{{item.avatar}}"></tui-lazyload-img>
    		<view class="tui-name">{{item.id +'-'+ item.name }}</view>
    	  </view>
    	</tui-list-cell>
      </tui-virtual-item>
    </tui-virtual-list>
    
     //数据列表可自行定义,示例文件请前往示例项目获取
    import list from '../../../utils/list.js'
    let virtualList;
    Page({
      data: {
        itemCount:100,
        startIndex: 0,
        endIndex: 0,
        disablePullUp: false,
        //显示列表
        virtualItems: [],
        //数据源
        items: list
      },
      onLoad(options) {
    
      },
      onReady() {
        virtualList = this.selectComponent('#virtualList')
        this.updated(this.data.items)
      },
      updated(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 + this.data.itemCount,
              name: item.name,
              avatar: item.avatar,
            }
          })
          this.data.items = this.data.items.concat(itemList)
          this.data.itemCount += 100
          this.updated(this.data.items)
          this.data.disablePullUp = false;
          wx.hideLoading()
        }, 1000)
        console.log('loadData', e.detail)
      },
      onChange(e) {
        const {
          startIndex,
          endIndex,
          items
        } = e.detail
        console.log('onChange', e.detail)
        if (this.data.startIndex !== startIndex || this.data.endIndex !== endIndex) {
          this.data.startIndex = startIndex;
          this.data.endIndex = endIndex;
          this.setData({
            virtualItems: items
          })
        }
      },
      onScrollToLower(e) {
        this.loadData(e)
        console.log('onScrollToLower', e.detail)
      },
      itemClick(e) {
        const item = e.currentTarget.dataset.item
        console.log(item)
      }
    })
    
    .tui-list__item {
      width: 100%;
      height: 100rpx;
      padding: 16rpx 30rpx;
      box-sizing: border-box;
      display: flex;
      align-items: center;
    }
    
    .tui-name {
      width: 90%;
      font-size: 32rpx;
      padding-left: 20rpx;
      padding-right: 40rpx;
      box-sizing: border-box;
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
    }
    
    // Make sure to add code blocks to your code group
    PageScroll 页面滚动使用示例

    通过 enablePageScroll 属性设置是否启用页面滚动,item-height 属性设置子项高度, itemBuffer 属性设置可视容器外加载的元素个数,background 属性设置容器背景色。

      <template>
      	<view class="container">
      		<tui-virtual-list enablePageScroll :item-height="120" :itemBuffer="50" background="#fff" ref="virtualList"
      			@change="onChange">
      			<tui-virtual-item @click="itemClick(item)" v-for="(item,index) in virtualItems" :key="index">
      				<tui-list-cell padding="0">
      					<view class="tui-list__item" :style="{height:itemHeight+'px'}">
      						<tui-lazyload-img width="72rpx" height="72rpx" radius="8rpx"
      							:src="item.avatar"></tui-lazyload-img>
      						<view class="tui-name">{{item.id +'-'+ item.name }}</view>
      					</view>
      				</tui-list-cell>
      			</tui-virtual-item>
      		</tui-virtual-list>
      		<tui-loadmore v-if="disablePullUp"></tui-loadmore>
      	</view>
      </template>
      
      <script>
      	import list from '@/utils/list.js'
      	let itemCount = 100
      	export default {
      		data() {
      			return {
      				startIndex: 0,
      				endIndex: 0,
      				disablePullUp: false,
      				//显示列表
      				virtualItems: [],
      				//数据源
      				items: list,
      				//组件传入为rpx值,组件内会转化为px,初始化事件返回px值
      				itemHeight: 60
      			}
      		},
      		onReady() {
      			this.updated(this.items)
      		},
      		methods: {
      			updated(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() {
      				if (this.items.length >= 5000 || 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,
      						}
      					})
      					this.items = this.items.concat(itemList)
      					itemCount += 100
      					this.updated(this.items)
      					this.disablePullUp = false;
      					uni.hideLoading()
      					uni.stopPullDownRefresh()
      				}, 1000)
      				console.log('loadData')
      			},
      			init(e) {
      				this.itemHeight = e.itemHeight
      			},
      			onChange(e) {
      				const {
      					startIndex,
      					endIndex,
      					items
      				} = e
      				console.log('onChange', e)
      				if (this.startIndex !== startIndex || this.endIndex !== endIndex) {
      					this.startIndex = startIndex;
      					this.endIndex = endIndex;
      					this.virtualItems = items
      				}
      			},
      			itemClick(item) {
      				console.log(item)
      			}
      		},
      		onPageScroll(e) {
      			// 当页面滚动时调用组件 onScroll 方法
      			const virtualList = this.$refs.virtualList
      			virtualList && virtualList.onScroll({
      				detail: e
      			})
      		},
      		onReachBottom() {
      			this.loadData()
      			console.log('onReachBottom')
      		},
      		onPullDownRefresh() {
      			itemCount = 0
      			this.items = []
      			this.loadData()
      			console.log('onPullDownRefresh')
      		}
      	}
      </script>
      
      <style>
      	.tui-list__item {
      		width: 100%;
      		height: 120rpx;
      		padding: 16rpx 30rpx;
      		box-sizing: border-box;
      		display: flex;
      		align-items: center;
      	}
      
      	.tui-name {
      		width: 90%;
      		font-size: 32rpx;
      		padding-left: 20rpx;
      		padding-right: 40rpx;
      		box-sizing: border-box;
      		white-space: nowrap;
      		overflow: hidden;
      		text-overflow: ellipsis;
      	}
      </style>
      	
      
       <view class="container">
           <tui-virtual-list enablePageScroll item-height="{{120}}" itemBuffer="{{50}}" background="#fff" id="virtualList" bindinit="init" bindchange="onChange">
             <tui-virtual-item bindclick="itemClick" data-item="{{item}}" wx:for="{{virtualItems}}" wx:key="index">
               <tui-list-cell padding="0">
                 <view class="tui-list__item" style="height: {{itemHeight}}px;">
                   <tui-lazyload-img width="72rpx" height="72rpx" radius="8rpx" src="{{item.avatar}}"></tui-lazyload-img>
                   <view class="tui-name">{{item.id +'-'+ item.name }}</view>
                 </view>
               </tui-list-cell>
             </tui-virtual-item>
           </tui-virtual-list>
           <tui-loadmore wx:if="{{disablePullUp}}"></tui-loadmore>
       </view>
      
       //数据列表可自行定义,示例文件请前往示例项目获取
      import list from '../../../utils/list.js'
      let virtualList;
      Page({
        data: {
          startIndex: 0,
          endIndex: 0,
          disablePullUp: false,
          //显示列表
          virtualItems: [],
          //数据源
          items: [...list],
          itemCount: 100,
          //传入为rpx值,组件内会转化为px,初始化事件返回值
          itemHeight: 60
        },
        onLoad(options) {
      
        },
        onReady() {
          virtualList = this.selectComponent('#virtualList')
          this.updated(this.data.items)
        },
        updated(items) {
          const startTime = Date.now()
          virtualList && virtualList.render(items, () => {
            const diffTime = Date.now() - startTime
            console.log(`success - render time: ${diffTime}ms`)
          })
        },
        init(e) {
          this.setData({
            itemHeight: e.detail.itemHeight
          })
        },
        loadData() {
          if (this.data.items.length >= 5000 || this.data.disablePullUp) return
          this.data.disablePullUp = true;
          wx.showLoading({
            title: '正在加载...'
          })
          setTimeout(() => {
            const itemList = list.map(item => {
              return {
                id: item.id + this.data.itemCount,
                name: item.name,
                avatar: item.avatar,
              }
            })
            this.data.items = this.data.items.concat(itemList)
            this.data.itemCount += 100
            this.updated(this.data.items)
            this.data.disablePullUp = false;
            wx.hideLoading()
            wx.stopPullDownRefresh()
          }, 1000)
          console.log('loadData')
        },
        onChange(e) {
          const {
            startIndex,
            endIndex,
            items
          } = e.detail
          console.log('onChange', e.detail)
          if (this.data.startIndex !== startIndex || this.data.endIndex !== endIndex) {
            this.data.startIndex = startIndex;
            this.data.endIndex = endIndex;
            this.setData({
              virtualItems: items
            })
          }
        },
        itemClick(e) {
          const item = e.currentTarget.dataset.item
          console.log(item)
        },
        onPageScroll(e) {
          // 当页面滚动时调用组件 onScroll 方法
          virtualList && virtualList.onScroll({
            detail: e
          })
        },
        onReachBottom() {
          this.loadData()
          console.log('onReachBottom')
        },
        onPullDownRefresh() {
          this.data.itemCount = 0
          this.data.items = []
          this.loadData()
          console.log('onPullDownRefresh')
        }
      })
      
      .tui-list__item {
        width: 100%;
        height: 120rpx;
        padding: 16rpx 30rpx;
        box-sizing: border-box;
        display: flex;
        align-items: center;
      }
      
      .tui-name {
        width: 90%;
        font-size: 32rpx;
        padding-left: 20rpx;
        padding-right: 40rpx;
        box-sizing: border-box;
        white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;
      }
      
      // Make sure to add code blocks to your code group

      # Slots

      tui-virtual-list 组件

      插槽名称 说明
      default 列表内容,由多个tui-virtual-item组成

      tui-virtual-item 组件

      插槽名称 说明
      default 自定义显示item项内容

      # Props

      tui-virtual-list 组件

      属性名 类型 说明 默认值
      treeData Array 树型菜单数据,数据格式参考文档代码演示部分或者示例 [ ]
      collapsible Boolean 是否可折叠 true
      triangle Boolean 是否显示三角箭头 true

      tui-virtual-item 组件

      属性名 类型 说明 默认值
      - - - -

      # Events

      tui-virtual-list 组件

      事件名 说明 回调参数
      init 初始化回调函数 { itemHeight: item项高度 px }
      change 数据变化时的回调函数 { e: 对象数据 }
      scroll 滚动时触发,使用scroll-view滚动时使用 { e: 对象数据 }
      scrolltoupper 滚动到顶部时触发,使用scroll-view滚动时使用 { e: 对象数据 }
      scrolltolower 滚动到底部时触发,使用scroll-view滚动时使用 { e: 对象数据 }

      tui-virtual-item 组件

      事件名 说明 回调参数
      click 点击时触发 { }

      # Methods

      如何调用方法详见 进阶用法 介绍

      tui-virtual-list 组件

      方法名 说明 传入参数
      render 用于动态加载数据 items, callback
      scrollTo 滚动到指定的位置 scrollOffset, callback
      scrollToIndex 根据索引值滚动到指定的位置 index, callback
      onScroll 启用页面滚动时需要手动设置 e
      //方法及参数详细说明
      
      /**
       * 更新组件
       * @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) 
      
      
      /**
       * 滚动时触发的事件,启用页面滚动时需要在 onPageScroll 中 手动设置
       * @param {Object} e 表示事件对象
       */
      onScroll(e) 
      

      # 预览

      请以移动端效果为准,touch事件目前尚未在PC端做兼容。

      # 特别说明

      该组件为 会员组件,非开源内容,需开通会员才可获取使用。

      # 线上程序扫码预览

      ThorUI组件库 H5二维码 ThorUI示例
      ThorUI组件库小程序码 H5二维码 ThorUI示例小程序码
      Last Updated: 11/4/2023, 2:12:48 PM