vue3.2 前端动态分页算法

发布于:2025-07-10 ⋅ 阅读:(33) ⋅ 点赞:(0)

背景

   1. 后台接口只是动态返回一个数组的数据,前端需要根据数据量的大小判断是否需要分页,页面高度固定
   2. 页面根据页数大小有不同的展示
     a. 只有一页  头部 + 内容 + 统计 + 尾部
     b. 多页
        i.  第一页 头部 + 内容 + 尾部
        ii. 中间页 内容 + 尾部
        iii. 最后一页 内容 + 统计 + 尾部

思路

	1. 先判断是否一页能满足 如果能满足 不做数据处理
	2. 不满足则肯定是多页
	    a. 先计算第一页的逻辑,将数组分为[第一页数据, 剩余数据]
	    b. 剩余数据只有两种情况
	      i. 符合尾页逻辑 直接将剩余数据放入最后一页
	     ii. 不符合尾页逻辑 递归实现中间页

页面情况

 s1 只有一页  不需要操作
 
 s2 多页
    a. 第一页因为要显示头部  所以高度为  540 - 50
    b. 中间页只显示内容      所以高度为  540
    c. 尾页因为要显示统计    所以高度为  540 - 50

核心代码

<template>
  <div class="container">
    <div class="page" v-for="(list, index) in lists" :key="index">
      <div class="top" v-if="index === 0">
        <VHead />
      </div>

      <div class="middle">
        <VTable :item="list" />
        <VTotal v-if="index === lists.length - 1" />
      </div>

      <div class="bottom">
        <VFooter />
      </div>
    </div>
  </div>
</template>

<script setup>
import { ref, onMounted, nextTick } from 'vue'
import VHead from './components/VHead.vue'
import VTable from './components/VTable.vue'
import VTotal from './components/VTotal.vue'
import VFooter from './components/VFooter.vue'
import { init } from './data/index.js'

const HEIGHT = 540

const list = init(5)
const lists = ref([])

const render = async () => {
  lists.value = [list]
  await nextTick()
  calculatePages()
}

const getTrs = () => {
  const trEls = document.querySelectorAll('.v-table tbody tr')
  let trHeights = []
  for (let i = 0; i < trEls.length; i++) {
    trHeights.push(trEls[i].offsetHeight)
  }
  const trHeightsTotal = trHeights.reduce((acc, cur) => acc + cur, 0)
  return {
    trHeights,
    trHeightsTotal
  }
}

const calculatePages = () => {
  const isSiglePage = getIsSinglePage()
  if (!isSiglePage) {
    const remainIndex = calculateFirstPage()
    lists.value = [list.slice(0, remainIndex)]
    calculateOtherPages(remainIndex)
  }
}

const getIsSinglePage = () => {
  const { trHeightsTotal } = getTrs()
  if (trHeightsTotal + 100 > HEIGHT) {
    return false
  }
  return true
}

const calculateFirstPage = () => {
  const { trHeights } = getTrs()
  const maxHeight = HEIGHT - 50
  let total = 0
  let index = 0
  for (let i = 0; i < trHeights.length; i++) {
    if (total + trHeights[i] > maxHeight) {
      break
    }
    total += trHeights[i]
    index = i
  }
  return index
}

const calculateOtherPages = (remainIndex) => {
  const { trHeights } = getTrs()
  const remainTrHeights = trHeights.slice(remainIndex)
  const remainTrTotal = remainTrHeights.reduce((acc, cur) => acc + cur, 0)
  if (remainTrTotal + 50 > HEIGHT) {
    let total = 0
    let index = 0
    for (let i = remainIndex; i < trHeights.length; i++) {
      if (total + trHeights[i] > HEIGHT) {
        break
      }
      total += trHeights[i]
      index = i
    }
    if (index) {
      lists.value.push(list.slice(remainIndex, index))
      calculateOtherPages(index)
    }
  } else {
    lists.value.push(list.slice(remainIndex))
  }
}

onMounted(() => {
  render()
})
</script>

<style lang="scss" scoped>
.container {
  display: flex;
  flex-direction: column;
}

.page {
  width: 800px;
  height: 590px;
  border: 1px solid #ccc;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  margin-bottom: 2px;
  overflow: hidden;

  .top,
  .bottom {
    height: 50px;
  }

  .middle {
    flex: 1;
    overflow: hidden;
  }
}
</style>

小结

最开始想的是通过AI实现,经过多次测试发现AI实现的有很多缺陷,甚至需求都不明白,最后只能自己一步一步实现,想了很多方案,最终在此方案下符合需求。
如果有更好的方案,欢迎交流

效果

在这里插入图片描述
在这里插入图片描述

完整代码


网站公告

今日签到

点亮在社区的每一天
去签到