网站推广的方法和渠道/即时热榜
ElementPlus中的分页逻辑与实现
分页是web开发中必不可少的组件,element团队提供了简洁美观的分页组件,配合table数据可以实现即插即用的分页效果。分页的实现可以分成两种,一是前端分页,二是后端分页。这两种分页分别适用于不同的业务场景,分页写了无数回了,但一直记不住,因此记录一下这两种分页效果的逻辑和实现。
一、前端分页
前端分页适用于数据量少的情况,向后端发起一次数据请求,前端处理分页。优点就是接口请求少,逻辑很简单,缺点很明显,处理大量数据时,效率极低。
前端分页是我非常喜欢的一种分页模式,最主要的原因就是代码简单。
现在来看看是怎么实现的。
首先看看最终的实现效果:
配合代码来看:
<template><div class="outer"><el-table :data="currentTableData" height="480" stripe border class="table"><el-table-column v-for="(item, index) in tableForm" :key="index" :prop="item.prop" :label="item.label":width="100" show-overflow-tooltip></el-table-column><el-table-column fixed="right" label="详细" width="100"><template #default="scope"><el-button link type="primary" size="small" @click="handleClick(scope.$index, scope.row)">查看</el-button></template></el-table-column></el-table><el-pagination class="pagination" small background layout="prev, pager, next" :total="totalItems"v-model:current-page="currentPage" @current-change="handelCurrentChange" :hide-on-single-page="paginationShow"style="margin-top: 20px;" /></div>
</template><script setup>
import { ref, onMounted, watch } from 'vue'
import { getAnalisisNolocalTableApi } from '@/apis/analysisNolocal'
import { ElMessage } from 'element-plus';
const tableData = ref([])
const tableForm = [// 表头数据
]// 点击每行的查看,展示详细事故信息
import mitt from '@/utils/mitt'
const emitter = mitt
const handleClick = (index, row) => {emitter.emit('showDrawer', row)// console.log(index, row)
}// 分页
const currentTableData = ref([])
const currentPage = ref(1)
const pageSize = 10
const totalItems = ref(0)
const paginationShow = ref(true)watch(tableData, (newVal, oldVal) => {currentPage.value = 1totalItems.value = tableData.value.lengthcurrentTableData.value = tableData.value.filter((item, index) => index < pageSize)// paginationShow.value = tableData.value.length > 10 ? true : false
})const handelCurrentChange = page => {currentPage.value = page// currentPage.value = 1const index = pageSize * (page - 1)const nums = pageSize * pageconst tables = []for (let i = index; i < nums; i++) {if (tableData.value[i]) tables.push(tableData.value[i])}currentTableData.value = tables
}const getData = async () => {try {const { data } = await getAnalisisNolocalTableApi()// console.log(data)tableData.value = data} catch (error) {ElMessage.error('请求接口报错')console.log(error)}
}
onMounted(async () => {getData()
})
</script><style lang="scss" scoped></style>
首先解释一下代码:
- 表格中的全部数据绑定的是tableData,获取tableData的方法是getData,在组件挂载前即调用
- 当前页面的表格数据是currentTableData
- 表格的表头是tableForm,这里根据自己的实际情况去写
接着看分页:
<el-pagination class="pagination" small background layout="prev, pager, next" :total="totalItems"v-model:current-page="currentPage" @current-change="handelCurrentChange" :hide-on-single-page="paginationShow"style="margin-top: 20px;" />
参数非常多,我们直接看elementplus给的api:
属性名 | 说明 | 类型 | 默认值 |
---|---|---|---|
small | 是否使用小型分页样式 | boolean | false |
background | 是否为分页按钮添加背景色 | boolean | false |
page-size / v-model:page-size | 每页显示条目个数 | number | — |
default-page-size | 每页默认的条目个数,不设置时默认为10 | number | — |
total | 总条目数 | number | — |
page-count | 总页数, total 和 page-count 设置任意一个就可以达到显示页码的功能;如果要支持 page-sizes 的更改,则需要使用 total 属性 | number | — |
pager-count | 设置最大页码按钮数。 页码按钮的数量,当总页数超过该值时会折叠 | number | 7 |
current-page / v-model:current-page | 当前页数 | number | — |
default-current-page | 当前页数的默认初始值,不设置时默认为 1 | number | — |
layout | 组件布局,子组件名用逗号分隔 | string | prev, pager, next, jumper, ->, total |
page-sizes | 每页显示个数选择器的选项设置 | object | [10, 20, 30, 40, 50, 100] |
popper-class | 每页显示个数选择器的下拉框类名 | string | ‘’ |
prev-text | 替代图标显示的上一页文字 | string | ‘’ |
prev-icon | 上一页的图标, 比 prev-text 优先级更高 | string / Component | ArrowLeft |
next-text | 替代图标显示的下一页文字 | string | ‘’ |
next-icon | 下一页的图标, 比 next-text 优先级更低 | string / Component | ArrowRight |
disabled | 是否禁用分页 | boolean | false |
teleported 2.3.13 | 是否将下拉菜单teleport至 body | boolean | true |
hide-on-single-page | 只有一页时是否隐藏 | boolean | false |
有这么几个参数很重要:
const currentPage = ref(1)
,绑定的属性是current-page / v-model:current-page,即当前页码,默认为1const totalItems = ref(0)
,绑定的属性是total,就是数据总数,根据tableData的长度来确定
还有一个事件很重要,即current-change
,就是当前页码发生变化的时候执行的事件,绑定的方法是handelCurrentChange,来看看这个方法做了什么事情
const handelCurrentChange = page => {currentPage.value = page// currentPage.value = 1const index = pageSize * (page - 1)const nums = pageSize * pageconst tables = []for (let i = index; i < nums; i++) {if (tableData.value[i]) tables.push(tableData.value[i])}currentTableData.value = tables
}
- 首先这个方法接收一个默认的参数page,其实就是当前的页码,把默认参数赋值给currentPage
- 获取当前页数据的起始索引,即index = pageSize * (page - 1),因为页码是从1开始,第一页的数据从第0条开始,所以其实索引应该是pageSize * (page - 1),这里的pageSize 就是每页数据要显示的条数
- 获取当前页最后一条数据的索引,即nums = pageSize * page
- 根据index和nums来获取当前页的数据
注意看,我还写了一个监听事件:
watch(tableData, (newVal, oldVal) => {currentPage.value = 1totalItems.value = tableData.value.lengthcurrentTableData.value = tableData.value.filter((item, index) => index < pageSize)// paginationShow.value = tableData.value.length > 10 ? true : false
})
这个代码写在这里是因为我还对数据做了筛选,筛选数据后,tableData发生变化,所以分页的总数和当前页都需要变化,这和我这里讲的前端分页关系不大
至此,就实现了前端分页的全部效果,还是挺简单的,总结一下,核心在于:
- 定义分页的参数
- 向后端获取总的数据
- 写好current-change方法
二、后端分页
其实后端分页才是正确的思路,因为正常的情况下,后端不会一下子把全部的数据都给前端,传输效率低而且也不安全。但后端分页相对来说要麻烦很多,不管咋样,还是记录一下
先看看我的分页结果:
都是用的测试数据,分页在右下角,其实在显示上没有任何差别,但逻辑完全不一样
1.后端代码
后端写了俩接口,我用node写的,一是获取列表总数,二是监听换页返回给前端当前页面的数据
代码如下:
// 分页
// 获取列表总数
exports.getAdminListLength = (req, res) => {const sql = "select * from users where identity = ?";db.query(sql, req.body.identity, (err, results) => {if (err) res.cc(err);res.send({length: results.length,});});
};// 监听换页,返回数据,参数为页码和身份
exports.returnListData = (req, res) => {// 每页显示10条,offset是起始处的偏移量const number = req.body.page * 10;const sql = `select * from users where identity = ? limit 10 offset ${number}`;db.query(sql, [req.body.identity, number], (err, results) => {if (err) res.cc(err);results.forEach((item) => {item.password = "";item.create_time = "";item.update_time = item.update_time.slice(0, 19);});res.send(results);});
};
获取列表总数没啥好说的,就是一个查询语句
主要看returnListData方法
其实前端给后端传递了两个参数,一个是当前的页码(page),一个是查询条件(identity)
看查询语句
const sql = `select * from users where identity = ? limit 10 offset ${number}`;
limit 10表示返回前10条数据
这里的offset很关键,表示从哪里开始返回10条数据,比如我想要查询第3页的数据,那么前端实际的page=3,传递给后端实际的page=page-1=2(这里的逻辑要理解一下),那么,第3页的数据应该是索引20-29的数据,这里的number=20,offset 20的意思就是从第20条开始取数据
后端的逻辑就是这样
2.前端代码
直接上代码
<template><BreadCrumb ref="breadCrumb" :item="item"></BreadCrumb><div class="table-wrapped"><div class="table-top"><div class="table-header"><div class="search-wrapped" style="display: flex"><el-input v-model="input1" class="w-50 m-2" placeholder="输入账号搜索" :prefix-icon="Search"@change="searchAdmin" /><!-- <el-button type="primary" @click="getAdmin" style="margin-left: 10px;" circle :icon="Refresh"title="重置列表"></el-button> --></div><div class="button-wrapped"><el-button type="primary" @click="create">添加产品管理员</el-button></div></div><div class="table-content"><el-table :data="tableData" border style="width: 100%"><el-table-column type="index" width="50" /><el-table-column prop="account" label="账号" /><el-table-column prop="name" label="姓名" /><el-table-column prop="sex" label="性别" /><el-table-column prop="department" label="部门" /><el-table-column prop="email" label="邮箱" /><el-table-column prop="update_time" label="更新时间" /><el-table-column label="操作" width="150"><template #default="scope"><el-button type="success" size="small"@click="handleEdit(scope.$index, scope.row)">编辑</el-button><el-button type="danger" size="small"@click="handleDelete(scope.$index, scope.row)">删除</el-button></template></el-table-column></el-table></div></div><div class="table-footer"><el-pagination :page-size="2" :current-page="paginationData.currentPage" :pager-count="5" :total="adminTotal":page-count="paginationData.pageCount" @current-change="currentPageChange" layout="prev, pager, next" /></div></div><CreateAdmin></CreateAdmin><EditAdmin></EditAdmin><DeleteAdmin></DeleteAdmin>
</template><script setup>
import { ref, onMounted, onBeforeUnmount } from 'vue'
import { Refresh, Search } from '@element-plus/icons-vue'
import BreadCrumb from '@/components/BreadCrumb.vue';
import CreateAdmin from '../components/CreateAdmin.vue'
import EditAdmin from '../components/EditAdmin.vue'
import DeleteAdmin from '../components/DeleteAdmin.vue';
import { getAdminAPI, searchUserAPI, getAdminListLengthAPI, returnListDataAPI } from "@/apis/userinfo";
import mitt from '@/utils/mitt'
import { ElMessage } from 'element-plus';
const emitter = mittconst item = ref({first: '用户管理',second: '产品管理员'
})
const input1 = ref('')
const tableData = ref([])const create = () => {emitter.emit('openCreateDialog', '添加产品管理员')
}const handleEdit = (index, row) => {emitter.emit('openEditDialog', { index, row, title: '编辑产品管理员' })// console.log('-----------', index, row)
}
const handleDelete = (index, row) => {emitter.emit('openDeleteDialog', { row })
}const getAdmin = async () => {const res = await getAdminAPI({ identity: '产品管理员' })if (res.status && res.status == 1) return ElMessage.error('获取数据出错')tableData.value = res// console.log(res)
}emitter.on('refreshAdminList', async () => {// getAdmin()getAdminListLength()tableData.value = await returnListDataAPI({ identity: '产品管理员', page: paginationData.value.currentPage - 1 })})
const searchAdmin = async () => {const res = await searchUserAPI({ account: input1.value })// console.log(res)tableData.value = res
}// 分页
const paginationData = ref({// 总页数pageCount: 1,// 当前页currentPage: 1,
})const adminTotal = ref(0)
const getAdminListLength = async () => {const res = await getAdminListLengthAPI({ identity: '产品管理员' })adminTotal.value = res.length// 每页显示10条数据,所以除以10paginationData.value.pageCount = Math.ceil(res.length / 10)
}// 默认获取第一页的数据
const getFirstPageList = async () => {tableData.value = await returnListDataAPI({ identity: '产品管理员', page: 0 })
}
const currentPageChange = async (val) => {// console.log(val)paginationData.value.currentPage = valtableData.value = await returnListDataAPI({ identity: '产品管理员', page: val - 1 })
}
onMounted(() => {// getAdmin()getAdminListLength()getFirstPageList()
})
onBeforeUnmount(() => {emitter.all.clear()
})
</script><style lang="scss" scoped></style>
代码挺长,我们只要关注表格和分页就行了
表格绑定的数据是tableData,注意,这里已经不是全部的数据了,而是当前页的数据
分页组件:
<el-pagination :page-size="10" :current-page="paginationData.currentPage" :pager-count="5" :total="adminTotal":page-count="paginationData.pageCount" @current-change="currentPageChange" layout="prev, pager, next" />
数据的总条目adminTotal根据后端的第一个接口获取,写了total属性page-count就可以不用写了
属性就不再详细介绍了,就关注current-change相关的方法
const currentPageChange = async (val) => {// console.log(val)paginationData.value.currentPage = valtableData.value = await returnListDataAPI({ identity: '产品管理员', page: val - 1 })
}
在前端分页的时候介绍了,current-change事件传递默认参数为当前页码,这个页码是需要给后端传递的非常重要的一个参数,实际传递给后端的page是当前页码-1后的值
还有一个需要注意的事,组件挂载时,应该默认显示第一页的数据,所以还需要写一个获取第一页数据的方法,即:
// 默认获取第一页的数据
const getFirstPageList = async () => {tableData.value = await returnListDataAPI({ identity: '产品管理员', page: 0 })
}
至此,后端分页的全部逻辑就完了
这玩意儿,还得常写常练,一段时间不写,直接忘光。。。。
相关文章:

ElementPlus中的分页逻辑与实现
ElementPlus中的分页逻辑与实现 分页是web开发中必不可少的组件,element团队提供了简洁美观的分页组件,配合table数据可以实现即插即用的分页效果。分页的实现可以分成两种,一是前端分页,二是后端分页。这两种分页分别适用于不同…...

实验01:静态路由配置实验
1.实验目的: 本次实验的主要目的是了解静态路由的配置和实现原理,熟悉路由器的基本操作,掌握在网络中进行静态路由配置的方法和技巧。 2.实验内容: 搭建网络拓扑,包括三台路由器和两台PC。配置路由器的IP地址和路由…...

C#中简单的继承和多态
今天我们来聊一聊继承,说实话今天也是我第一次接触。 继承的概念是什么呢?就是一个类可以继承另一个类的属性和方法(成员) 继承是面向对象编程中的一个非常重要的特性。 好了,废话不多说,下面切入正题&a…...

15、lambda表达式、右值引用、移动语义
前言 返回值后置 auto 函数名 (形参表) ->decltype(表达式) lambda表达式 lambda表达式的名称是一个表达式 (外观类似函数),但本质绝非如此 语法规则 [捕获表] (参数表) 选项 -> 返回类型 { 函数体; }lambda表达式的本质 lambda表达式本质其实是一个类…...

spring boot 实现直播聊天室(二)
spring boot 实现直播聊天室(二) 技术方案: spring bootnettyrabbitmq 目录结构 引入依赖 <dependency><groupId>io.netty</groupId><artifactId>netty-all</artifactId><version>4.1.96.Final</version> </dependency>Si…...

alibaba fastjson GET List传参 和 接收解析
之前一直都是 get传的都是单字符串(例如 xxxxxxxxx?name{name};name“woaini”;),并没有传list的. GET List传参 问题场景 String url"xxxxxxxx?id{id}"; HashMap<String,Object> param new HashMap<>(); param.pu…...

API自动化测试是什么?我们该如何做API自动化测试呢?
API测试已经成为测试工作中的常规任务之一。为了提高测试效率并减少重复的手工操作,API自动化测试变得越来越重要。本文总结了API自动化测试方面的经验和心得,旨在与读者分享。 掌握自动化技能已经成为高级测试工程师的必备技能。敏捷和持续测试改变了传…...

PyTorch 的 10 条内部用法
欢迎阅读这份有关 PyTorch 原理的简明指南[1]。无论您是初学者还是有一定经验,了解这些原则都可以让您的旅程更加顺利。让我们开始吧! 1. 张量:构建模块 PyTorch 中的张量是多维数组。它们与 NumPy 的 ndarray 类似,但可以在 GPU …...

Django、Echarts异步请求、动态更新
前端页面 <!DOCTYPE html> <html><head><meta charset"utf-8"><title>echarts示例</title> <script src"jquery.min.js"></script><script type "text/javascript" src "echarts.m…...

Mac部署Odoo环境-Odoo本地环境部署
Odoo本地环境部署 安装Python安装Homebrew安装依赖brew install libxmlsec1 Python运行环境Pycharm示例配置 Mac部署Odoo环境-Odoo本地环境部署 安装Python 新机,若系统没有预装Python,则安装需要版本的Python 点击查询Python官网下载 安装Homebrew 一…...

【✅面试编程题:如何用队列实现一个栈】
✅面试编程题:如何用队列实现一个栈 💡典型回答 💡典型回答 使用两个队列可以实现一个栈,一个队列用来存储栈中的元素,另一个队列用来在pop操作时暂存元素。 上才艺: import java.util.LinkedList; impo…...

Windows本地的RabbitMQ服务怎么在Docker for Windows的容器中使用
1. 进入管理界面 windows安装过程请访问:Windows安装RabbitMQ、添加PHP的AMQP扩展 浏览器访问:http://127.0.0.1:15672/ 2. 创建虚拟主机 上面访问的是 RabbitMQ 的管理界面,可以在这个界面上进行一些操作,比如创建虚拟主机、…...

YOLOv5改进 | 2023卷积篇 | AKConv轻量级架构下的高效检测(既轻量又提点)
一、本文介绍 本文给大家带来的改进内容是AKConv是一种创新的变核卷积,它旨在解决标准卷积操作中的固有缺陷(采样形状是固定的),AKConv的核心思想在于它为卷积核提供了任意数量的参数和任意采样形状,能够使用任意数量…...

微信小程序:模态框(弹窗)的实现
效果 wxml <!--新增(点击按钮)--> <image classimg src"{{add}}" bindtapadd_mode></image> <!-- 弹窗 --> <view class"modal" wx:if"{{showModal}}"><view class"modal-conten…...

uniapp交互反馈api的使用示例
官方文档链接:uni.showToast(OBJECT) | uni-app官网 1.uni.showToast({}) 显示消息提示框。 常用属性: title:页面提示的内容 image:改变提示框默认的icon图标 duration:提示框在页面显示多少秒才让它消失 添加了image属性后。 注…...

XUbuntu22.04之HDMI显示器设置竖屏(一百九十八)
简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长! 优质专栏:Audio工程师进阶系列【原创干货持续更新中……】🚀 优质专栏:多媒…...

如何用 Cargo 管理 Rust 工程系列 甲
以下内容为本人的学习笔记,如需要转载,请声明原文链接 微信公众号「ENG八戒」https://mp.weixin.qq.com/s/ceMTUzRjDoiLwjn_KfZSrg 这几年 Rust 可谓是炙手可热的新兴编程语言了,而且被投票为最受程序员喜爱的语言。它很现代,专门…...

Windows下ping IP+端口的方法
有两种方法: 1. windows 开通 telnet 参考: https://zhuanlan.zhihu.com/p/570982111 2. 安装插件 参考:Windows下ping IP端口的方法 推荐使用第二种。...

【python】os.getcwd()函数详解和示例
os.getcwd() 是 Python 的一个内建函数,用于获取当前工作目录的路径。这个函数属于 os 模块,需要导入这个模块才能使用它。 import os data_rootos.path.abspath(os.path.join(os.getcwd(),"../.."))# get data root path data_root1os.path.…...

Linux(二十一)——virtualenv安装成功之后,依然提示未找到命令(-bash: virtualenv: 未找到命令)
Linux(二十一)——virtualenv安装成功之后,依然提示未找到命令(-bash: virtualenv: 未找到命令) 解决办法: 创建软连接 ln -s /usr/local/python3/bin/virtualenv /usr/bin/virtualenv...

RNN介绍及Pytorch源码解析
介绍一下RNN模型的结构以及源码,用作自己复习的材料。 RNN模型所对应的源码在:\PyTorch\Lib\site-packages\torch\nn\modules\RNN.py文件中。 RNN的模型图如下: 源码注释中写道,RNN的数学公式: 表示在时刻的隐藏状态…...

Qt 文字描边(基础篇)
项目中有时需要文字描边的功能 1.基础的绘制文字 使用drawtext处理 void MainWindow::paintEvent(QPaintEvent *event) {QPainter painter(this);painter.setRenderHint(QPainter::Antialiasing, true);painter.setRenderHint(QPainter::SmoothPixmapTransform, true);painte…...

.360勒索病毒解密方法|勒索病毒解决|勒索病毒恢复|数据库修复
导言: 在数字化时代,.360勒索病毒如影随形,威胁个人和组织的数据安全。本文将深入介绍.360病毒的特征、威胁,以及如何有效地恢复被加密的数据文件,同时提供预防措施,助您更好地保护数字资产。如不幸感染这…...

Nginx(四层+七层代理)+Tomcat实现负载均衡、动静分离
一、Tomcat多实例部署 具体步骤请看我之前的博客 写文章-CSDN创作中心https://mp.csdn.net/mp_blog/creation/editor/134956765?spm1001.2014.3001.9457 1.1 访问测试多实例的部署 1.2 分别在三个tomcat服务上部署jsp的动态页面 mkdir /usr/local/tomcat/webapps/test vim …...

【前端】vscode 相关插件
一 插件: 01、ESLint 用来识别并检查ECMAScript/JavaScript 代码的工具 02、Prettier 用来格式化代码,如.js、.vue、css等都可以进行格式化 03、Vetur 用来识别并高亮vue语法 04、EditorConfig 用来设置vscode的编程行为 二、安装依赖 01、…...

【MySQL】MySQL库的增删查改
文章目录 1.库的操作1.1创建数据库1.2创建数据库案例 2.字符集和校验规则2.1查看系统默认字符集以及校验规则2.2查看数据库支持的字符集2.3查看数据库支持的字符集校验规则2.4校验规则对数据库的影响 3.操纵数据库3.1查看数据库3.2显示创建语句3.3修改数据库3.4数据库删除3.5备…...

基于基于深度学习的表情识别人脸打分系统
1.研究背景与意义 项目参考AAAI Association for the Advancement of Artificial Intelligence 研究背景与意义 随着人工智能技术的快速发展,深度学习在计算机视觉领域取得了巨大的突破。表情识别是计算机视觉领域的一个重要研究方向,它可以通过分析人…...

Linux|操作系统|Error: Could not create the Java Virtual Machine 报错的解决思路
现在都流行kubernetes这样的云原生了,因此,很多Java微服务也都集成到类似kubernetes这样的环境下了,毫无疑问的,kubernetes会省去很多环境问题,而最近在部署一个二进制Java项目的时候,遇到了Error: Could n…...

K8S学习指南-minikube的安装
简介 Minikube 是一个用于在本地开发环境中运行 Kubernetes 集群的工具。它允许开发人员在单个节点上体验 Kubernetes,无需配置复杂的生产环境。本指南将详细介绍在 Windows、CentOS 和 Ubuntu 系统上安装 Minikube 的步骤。 1. Windows 系统安装 1.1 ࿱…...

恒创科技:有哪些免费的CDN加速服务
CDN加速技术已经成为提升网站性能和用户体验的重要手段之一。许多网站都使用CDN来加速内容传输,提高网站的响应速度和可用性。然而,对于许多小型企业和个人网站来说,使用CDN服务需要支付一定的费用。那么,有没有免费的CDN加速服务…...