Vue3+Elementui Plus表格数据的 滚动加载 | 分页加载

Vue3滚动加载 | 分页加载

说明

    示例以 elementui plus2.9.0+ 和 vue3的代码,主要用于滚动加载,分页加载的数据也可以使用这个数据,也就是把数据分割了。代码可能存在某些误差,去掉了不用的东西,有些代码简化了写,分页已被注释,需要的可以自行选择。

common.js

import { isRef, unref } from "vue";

/**
 * 集合排序(没用,需要的可以使用)
 * 使用参考:tableData.value?.sort(listSort(['jobno','jobn'],['asc','asc']));
 */
export const listSort = (props, orders = [])=>{
  return (a, b) => {
    for (let i = 0; i < props.length; i++) {
      const prop = props[i];
      const order = orders[i] || 'asc';

      // 处理null
      if (a[prop] == null) return 1;
      if (b[prop] == null) return -1;

      // 比较属性值
      let compareResult = null;
      if (typeof a[prop] === 'string') {
        compareResult = a[prop].localeCompare(b[prop]);
      } else {
        compareResult = a[prop] - b[prop];
      }

      // 根据排序方向调整结果
      if (order === 'desc') compareResult *= -1;
      if (compareResult !== 0) return compareResult;
    }
    return 0;
  };
}
/**
 * 分页分割数据
 *    传参:
 *      listRef:需要分页的总数居
 *      pageTotal:需要根据多少条数分页,默认为20条
 *      tablePageRef:传递的表格分页的对象,用于数据返回,为空时返回一个对象,不为空时直接赋值
 *      currentPage:当前页,默认获取为第一页
 *      isQuery:是否是根据当前页去查询数据,需要传递 currentPage
 *      isLoad:是否是滚动加载,滚动加载|分页加载,默认为true滚动加载
 *    使用方式:
 *      const tablePage = reactive({
 *        pageSize: 0, //总页数
 *        currentPage: 1, //当前页
 *        total: 0,//总数
 *        pageTotal: 0,//每页页数
 *        resultData: [], //分割前的集合
 *        resultTableData: [], //分割后的集合
 *        currentTableData: [], //当前集合
 *      })
 *      const scrollTop = ref(0);
 *      const isScrollBottom = computed(()=>{})
 *      const handleScroll = ({ scrollTop:scroll })=>{}
 *      <el-table ref="tableRef" @scroll="handleScroll" >
 */
export const usePageFc = ({isQuery=false,listRef=[],pageTotal=20,tablePageRef,currentPage = 1,isLoad = true})=>{
  const list = unref(listRef);
  const tablePage = isRef(tablePageRef)?tablePageRef.value:tablePageRef;
  if(tablePage){
    if(!isQuery){
      const result = [];
      for (let i = 0; i < list?.length; i += pageTotal) {
        result.push(list.slice(i, i + pageTotal));
      }
      tablePage.resultTableData = reactive(lodash.cloneDeep(result));
      tablePage.resultData = list || [];
      tablePage.total = list.length || 0;
      tablePage.pageSize = result.length || 0;
      tablePage.pageTotal = pageTotal;
    }
    if(currentPage <= tablePage.pageSize){
      tablePage.currentTableData = tablePage.resultTableData[currentPage-1]
      tablePage.currentPage = currentPage;
    }else{ //末页处理
      if(isLoad){ //滚动加载
        tablePage.currentTableData = []
        tablePage.currentPage = tablePage.pageSize;
      }else{ //分页加载
        tablePage.currentTableData = tablePage.resultTableData[tablePage.pageSize-1]
        tablePage.currentPage = tablePage.pageSize;
      }
    }
    return null;
  }else{
    return tablePage
  }
}

index.vue

<template>
	<div class="table">
		<el-table ref="tableRef" v-loading="loading" :data="tableData" @scroll="handleScroll" :row-key="row => `${row.id}`">
		</el-table>
	</div>
	<div class="pagination">
        <!--
           pager-count:总页数
           total:总条目数
           page-size:每页显示条目数
           pager-count:最大页码数按钮,超过的显示...
           hide-on-single-page: 只有一页时是否隐藏分页
       -->
        <!-- <el-pagination
            v-model:current-page="search.pageNum"
            v-model:page-size="search.pageSize"
            :pager-count="pageCount || 0"
            @update:page-size="handleSizeChange"
            @update:current-page="handleCurrentChange"
            :hide-on-single-page="false"
            :page-sizes="[10, 20, 30, 50, 100,tableData?.length]"
            size="small"
            :disabled="false"
            :background="false"
            layout="total, slot, prev, pager, next, jumper"
            :total="page.total"
        >
          <template #default>
            <el-select style="margin-left: 1.2rem;" size="small"
                       v-model="search.pageSize"
                       @change="handleSizeChange">
              <el-option label="10条/页" :value="10"/>
              <el-option label="20条/页" :value="20"/>
              <el-option label="30条/页" :value="30"/>
              <el-option label="50条/页" :value="50"/>
              <el-option label="100条/页" :value="100"/>
              <el-option label="全部" :value="page.total"/>
            </el-select>
          </template>
        </el-pagination> -->
      </div>
</template>
<script setup>	
	import { computed, reactive, ref, onMounted } from "vue";
	import { usePageFc } from "@/utils/common";
	
	const tableRef = ref(null);
	const loading = ref(false);
	const tablePage = reactive({
  		pageSize: 0, //总页数
  		currentPage: 1, //当前页
 		total: 0,//总数
  		pageTotal: 0,//每页页数
  		resultData: [], //分割前的集合
  		resultTableData: [], //分割后的集合
  		currentTableData: [], //当前集合
	})
	const tableData = ref([]);
	/**
 	 * 获取所有集合
 	 *  relist:用于每次调用getList()获取最新的数据,否则通过点击事件触发getList()可能会存在数据残留导致数据异常
 	 */
	const getList = (relist = true)=>{
		if(relist){
    		tableData.value = [];
  		}
  		loading.value = true;
		//发送一个axios请求获得集合(省略),可以使用 async/await
		const array = [];
			
  		usePageFc({listRef: array,pageTotal: 50,tablePageRef: tablePage})
  		tableData.value.push(...tablePage.currentTableData);
 		loading.value = false
	}
	/**
 	 * 鼠标下滑滚动条底部触发事件
 	 */
	const scrollTop = ref(0);
	const isScrollBottom = computed(()=>{
  		const element = tableRef.value?.$el.querySelector('.el-			scrollbar__wrap') || {}; //.el-table__body-wrapper
  		const scrollHeight = element.scrollHeight; // 内容总高度
  		const clientHeight = element.clientHeight; // 可视高度
  		return scrollHeight - scrollTop.value <= clientHeight + 1; //触底条件(+1 避免浮点数误差)
	})
	/**
	 * 在表格中滑动滚动条触发的方法
	 */
	const handleScroll = ({ scrollTop:scroll })=>{
  		scrollTop.value = scroll;
  		if (isScrollBottom.value) {
    		usePageFc({isQuery: true,tablePageRef: 					tablePage,currentPage: tablePage.currentPage+1})
    		tableData.value.push(...tablePage.currentTableData);
  		}
	}
	/**
	 * 第一次加载页面的时候调用查询方法
	 */
	getList();
	
	onMounted(()=>{
  		
	})

	//- - - - - - - - - - - - - -
	//分页处理相关,赋值变量不对,这个是后端分页相关,参考使用
	const search = ref({
 		pageNum: 1, //当前页
        pageSize: 20, //查询条数
        sortList: [], //sortList 表格排序集合
        filter: null
	})
	const page = ref({
		total: 0,//总条数
        pages: 0,//总页数
	})
	/**
	 * 计算分页的...隐藏显示,返回值必须是奇数,且范围在5到21之间
 	*/
	const pageCount = computed(()=>{
  		if(page.value.pages<=10){
    		return 9;
  		}
  		return Math.round(page.value.pages/2) || 0;
	})
	/**
 	* 切换分页条件时的分页条数
 	*/
	const handleSizeChange = (val) => {
 		if(val){
    		search.value.pageSize = val
   	 		getList();
  		}
	}
	/**
 	 * 下一页时的当前页数
 	 */
	const handleCurrentChange = (val) => {
 	 	if(val){
    		search.value.pageNum = val
    		getList();
  		}
	}
</script>

<style scoped lang="scss">
/* 分页标签样式 */
.pagination {
    margin: 1vh;
    display: flex;
    justify-content: flex-end;
  }
</style>
Vue 3中的Element UI Plus是一个基于Vue 3的组件库,它是Element UI的升级版本,提供了许多现代化的UI组件,包括`el-table`。在`el-table`中实现虚拟滚动(Virtual Scroll)是一种优化大数据表格渲染的技术,它通过只渲染可视区域内的行来提高性能。 在Vue 3Element UI Plus中,实现虚拟滚动可以通过`v-infinite-scroll`指令来完成。这个指令允许你在表格滚动到接近底部时触发加载更多数据的操作,而不需要一次性加载所有数据。然而,需要注意的是,Element UI Plus本身并不直接提供一个虚拟滚动实现,你可能需要结合其他的虚拟滚动库,比如`v-virtual-scroller`,来实现这一功能。 使用虚拟滚动库,你可以将`el-table`包裹在虚拟滚动组件中,并提供必要的数据和方法来处理数据加载和渲染。这样可以显著减少DOM操作,提高大数据表格的渲染性能。 以下是使用虚拟滚动的一个基本示例: ```vue <template> <v-virtual-scroller :data="tableData"> <template v-slot="{ item }"> <el-table :data="item" style="width: 100%"> <!-- 表格列定义 --> <el-table-column prop="date" label="日期" width="180"></el-table-column> <!-- 其他列定义 --> </el-table> </template> </v-virtual-scroller> </template> <script> import { ref } from &#39;vue&#39;; import { ElTable, ElTableColumn } from &#39;element-plus&#39;; import { VVirtualScroller } from &#39;v-virtual-scroller&#39;; export default { components: { VVirtualScroller, ElTable, ElTableColumn }, setup() { const tableData = ref([]); // 假设这里有一个方法来加载数据 const loadData = () => { // 更新tableData或分页加载更多数据 }; return { tableData, loadData }; } }; </script> ``` 在上述示例中,`v-virtual-scroller`是虚拟滚动组件,`el-table`是Element UI Plus表格组件,它会根据数据更新来动态渲染表格的每一行。`v-slot`指令用于定义虚拟滚动的内容模板,其中`item`代表每个渲染的行的数据
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值