封装uniapp的虚拟列表组件

一、新建一个virtual-list.vue

<template>
  <!-- 虚拟列表 -->
  <view>
    <scroll-view :scroll-top="scrollTop" class="scroll-container" scroll-y="true" @scroll="scrollEvent"
      :style="{ height: containerHeight }">
      <!--可视区域里所有数据的渲染区域-->
      <view class="list" :style="{ top: top + 'px', ...customStyle }">
        <!--单条数据渲染区域-->
        <view v-for="(item, index) in showList" :key="index">
          <slot name="item" :row="item"></slot>
        </view>
      </view>
    </scroll-view>
  </view>
</template>

<script>
// 使用示例
// <virtual-list :sourceData="listAll" containerHeight="calc(100vh - 196rpx)" :itemHeight="200" :showNum="5" :customStyle="{ padding: '30rpx' }">
// 			<template v-slot:item="{ row }">
//       ......your code
// 			</template>
// </virtual-list>
// 刷新组件
// this.$refs.virtualList.refresh()
export default {
  props: {
    // 数据源
    sourceData: {
      type: Array,
      default: () => [],
      required: true
    },
    // 滚动容器总高度
    containerHeight: {
      type: String,
      default: '200px',
    },
    //每条数据所占高度
    itemHeight: {
      type: Number,
      default: 200,
      required: true
    },
    //每次加载到可视区域的数量,itemHeight X showNum 要大于可视区域高度 ,否则页面滚动不了
    showNum: {
      type: Number,
      default: 10,
      required: true
    },
    // 自定义列表样式
    customStyle: {
      type: Object,
      default: () => ({})
    }
  },
  data() {
    return {
      showList: [],  //可视区域显示的数据				
      top: 0, //偏移量
      scrollTop: 0,  //卷起的高度
      startIndex: 0,  //可视区域第一条数据的索引
      endIndex: 0,  //可视区域最后一条数据后面那条数据的的索引,因为后面要用slice(start,end)方法取需要的数据,但是slice规定end对应数据不包含在里面
    }
  },
  created() {
    //计算可视区域数据
    this.getShowList()
  },
  methods: {
    //计算可视区域数据
    getShowList() {
      this.startIndex = Math.floor(this.scrollTop / this.itemHeight)   //可视区域第一条数据的索引
      this.endIndex = this.startIndex + this.showNum   //可视区域最后一条数据的后面那条数据的索引
      this.showList = this.sourceData.slice(this.startIndex, this.endIndex)  //可视区域显示的数据,即最后要渲染的数据。实际的数据索引是从this.startIndex到this.endIndex-1
      this.top = this.scrollTop - (this.scrollTop % this.itemHeight)  //在这需要获得一个可以被itemHeight整除的数来作为item的偏移量,这样随机滑动时第一条数据都是完整显示的
    },
    //区域滚动事件
    scrollEvent(e) {
      this.scrollTop = e.detail.scrollTop
      this.getShowList()
    },
    // 刷新组件
    refresh() {
      setTimeout(() => {
        this.getShowList()
        this.scrollTop = 0
      })
    }
  }
}
</script>

<style scoped lang='scss'>
.scroll-container {
  position: relative;
  width: 100%;

  .list {
    position: absolute;
    width: 100%;
  }
}
</style>

 二、使用(下方代码是我使用的场景,你们可以自定义插槽中的内容)

<virtual-list ref="virtualList" :sourceData="taskList" containerHeight="calc(100vh - 196rpx)" :itemHeight="200"
			:showNum="5" :customStyle="{ padding: '30rpx' }">
			<template v-slot:item="{ row }">
				<view class="card">
					<view class="title">公章申请</view>
					<view class="row">
						<view class="fileds">创建日期:</view>
						<view class="content">2022-09-18 23:20:14</view>
					</view>
					<view class="row">
						<text class="fileds">申请人:</text>
						<text class="content">{{ row.name }}</text>
					</view>
					<view class="entry">
						<div class="name">查看详情</div>
						<div class="icon">&gt;</div>
					</view>
				</view>
			</template>
		</virtual-list>

 三、参数说明

属性

 sourceData:接收列表数据,传入数组即可

containerHeight:滚动容器的高度,接收例如 200px 的字符串

itemHeight:每条数据所占高度,传入数字,尽量在每一行的高度一致的列表使用,行高度差距非常大时不建议使用

showNum:滚动列表中能看到的行数量,保证 showNum *  itemHeight 大于 containerHeight  即可,可以自行调整数值,滚动顺滑即可

customStyle:自定义列表样式,接收style对象

方法

组件上定义ref="virtualList"

比例tab切换列表重新赋值后使用this.$refs.virtualList.refresh()刷新列表即可

作用域插槽

item

参数row, 数组遍历后单项的数据

  • 6
    点赞
  • 36
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
通过uni-app的easycom,可以将组件引入精简为一步。只要组件安装在项目的components目录下,并符合components/组件名称/组件名称.vue目录结构,就可以直接在页面中使用,无需引用和注册。 在封装组件时,需要注意props可以是数组或对象,用于接收来自父组件的数据。在HTML中,属性名称是大小写不敏感的,所以浏览器会将所有大写字符解释为小写字符。因此,在封装组件时属性名为contentText,在传值时应为content-text。 以下是一些常用的uniapp封装组件的示例代码: 1. 空数据占位图组件: ``` <template> <view class="fq-empty"> <image src="/static/image/empty-view.png"></image> <text class="">{{emptyText}}</text> </view> </template> <script> export default { props: { emptyText: { type: String, default: '什么都没有', } }, } </script> <style> .fq-empty { display: flex; flex-direction: column; align-items: center; justify-content: center; font-size: 16px; } .fq-empty image { width: 300rpx; height: 300rpx; margin: 30rpx; } </style> ``` 2. 分页组件: ``` <template> <view> <!-- 分页内容 --> </view> </template> <script> export default { props: { total: { type: Number, default: 0, }, pageSize: { type: Number, default: 10, }, currentPage: { type: Number, default: 1, } }, methods: { // 分页操作的方法 } } </script> <style> /* 样式 */ </style> ``` 3. 导航栏组件: ``` <template> <view> <!-- 导航栏内容 --> </view> </template> <script> export default { props: { title: { type: String, default: '', }, showBack: { type: Boolean, default: false, } }, methods: { // 导航栏相关操作的方法 } } </script> <style> /* 样式 */ </style> ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值