Vue b-pagination如何在对应数据不存在时隐藏对应分页按钮
Bootstrap Vue 的
b-pagination分页按钮渲染逻辑完全由传入的total-rows、per-page参数驱动,page 插槽仅用于替换按钮内部的显示内容,不会从组件的底层渲染逻辑移除对应按钮的DOM节点。即使插槽内返回空内容,按钮的基础结构依然会生成,最终就出现了无内容的空白占位按钮。
根据你的业务里无效分页按钮的分布场景,可以选择对应方案:
方案1:无效页为末尾连续场景(即从某一页开始后面全是无内容的页)
直接在组件计算逻辑层面限制最大渲染页数,让组件根本不会生成无内容的按钮,从根源解决问题:
- 新增计算属性,逐页校验是否有对应有效内容,一旦遇到第一页无内容,就截止计算最大有效页数:
computed: { // 计算存在有效内容的最大页码 validMaxPage() { for (let page = 1; page <= this.submissionFiles.length; page++) { // 校验当前页是否存在匹配当前学生页的有效数据 const hasValidContent = Boolean( this.submissionFiles[page - 1]?.[this.currentStudentPage - 1] ) // 遇到第一个无内容的页,返回上一页作为最大有效页 if (!hasValidContent) { return page - 1 } } // 所有页都有有效内容时,返回数组总长度 return this.submissionFiles.length } } - 替换组件的
total-rows入参,把原来的全量数组长度改成基于有效页数计算的值:<!-- 原来的 :total-rows="submissionFiles.length" 替换成下面的写法 --> <b-pagination :total-rows="validMaxPage * perPage" <!-- 其他原有配置保持不变 --> >
这种方式因为从组件参数层面限制了总页数,组件生成的按钮全是有有效内容的,不会出现空白按钮。
方案2:无效页为非连续分布场景(即中间夹杂无内容的页)
因为b-pagination本身默认是生成从1到N的连续页码,不支持跳过中间的无效页,有两种实现路径:
路径A:基于计算属性手动生成有效页列表,替代组件自动的连续页码逻辑
不依赖组件的自动连续页码生成能力,完全自己控制要渲染的分页按钮:
- 先计算当前场景下所有存在有效内容的页码列表:
computed: { // 筛出所有有有效内容的页码 validPageList() { const result = [] this.submissionFiles.forEach((fileItem, index) => { const pageNum = index + 1 const hasContent = Boolean(fileItem?.[this.currentStudentPage - 1]) if (hasContent) { result.push(pageNum) } }) return result } } - 基于这个有效页列表,自定义渲染分页按钮,直接跳过无内容的页,从根源上不生成对应的DOM。如果还是想保留b-pagination的样式,也可以配合手动渲染的结构复用组件的分页类名,实现和原生分页一致的视觉效果。
路径B:兼容保留b-pagination原生结构,通过CSS隐藏无效按钮
如果不想改动原有组件结构,可以配合插槽标记+CSS隐藏的方式实现无内容按钮的视觉隐藏:
- 在page插槽内,对无有效内容的页打标记:
<template v-slot:page="{ page, active }"> <span v-if="!submissionFiles[page - 1]?.[currentStudentPage - 1]" class="invalid-page-marker"></span> <span v-else> {{ submissionFiles[page - 1][currentStudentPage - 1].order }} </span> </template> - 新增CSS规则,把带标记的无效按钮对应的父级节点隐藏:
/* 隐藏标记本身 */ .b-pagination .invalid-page-marker { display: none; } /* 找到包裹标记的分页li元素,整体隐藏 */ .b-pagination li:has(.invalid-page-marker) { display: none !important; }
注意:这种方式依赖CSS的
:has选择器,仅兼容较新版本浏览器,低版本场景不适用。而且本质是CSS隐藏DOM,不是从渲染逻辑上阻止DOM生成。
你原有插槽的取值逻辑存在空指针报错风险,当submissionFiles[page-1]为undefined时,直接访问内层数组会抛出错误,建议统一改成可选链的写法:
<!-- 原来的取值逻辑 --> {{ submissionFiles[page - 1][currentStudentPage - 1] && submissionFiles[page - 1][currentStudentPage - 1].order }} <!-- 优化后避免报错的写法 --> {{ submissionFiles[page - 1]?.[currentStudentPage - 1]?.order }}
另外你给组件加的:key="currentQuestionPage"属性没必要,会导致currentQuestionPage变化时整个分页组件重新渲染,增加不必要的性能开销,因为currentQuestionPage本身就是组件绑定的v-model值,不需要额外强制重渲染。
内容的提问来源于stack exchange,提问作者Eric

