✨ 前后端分页不再愁:解密 Vue 组件如何优雅处理页码转换 ✨

✨ 前后端分页不再愁:解密 Vue 组件如何优雅处理页码转换 ✨

各位前端小伙伴们,后端老铁们,大家好!👋 在上一篇博客中,我们一起经历了一场因页码索引不匹配引发的“API查无数据”的惊魂探案。今天,我们要把目光投向一个“正面典型”——StockTotalTable.vue 组件。这个组件同样面临前端1-indexed页码与后端0-indexed页码的挑战,但它却处理得游刃有余,数据请求一切正常。🎉

它是怎么做到的呢?让我们一起揭开它神秘的面纱,学习一下优雅处理分页页码的正确姿势!

📖 StockTotalTable.vue 页码处理核心逻辑总结

处理环节 ⚙️关键代码/逻辑 💡效果/目的 🎯
状态初始化listQuery.page: 1组件内部状态维护用户视角的页码 (1代表第一页)
API 调用时page: this.listQuery.page - 1 (在 getList 方法内,调用API函数前)核心转换:将1-indexed页码转换为0-indexed,确保发送给后端的是0代表第一页。
分页组件交互handleChangePage(page: number) { this.listQuery.page = page } 后调用 getListElement UI分页组件返回1-indexed页码,更新内部状态,API调用时仍会进行 -1 转换。
搜索时handleSearch() { this.listQuery.page = 1 } 后调用 getList搜索后重置到用户视角的第一页,API调用时转换为0-indexed的第0页。

🗺️ StockTotalTable.vue 页码处理流程图

组件加载 / 用户操作
(如搜索, 点击分页)
更新内部状态 'listQuery.page'
(用户视角的1-indexed页码, 如 page=1)
调用 'getList()' 方法
在 'getList()' 内部,
准备API请求参数
计算实际请求页码:
apiPage = listQuery.page - 1
调用API函数
listConsignmentSummaryByPageWithSearch(..., { page: apiPage, ... })
API函数发送HTTP请求
请求体中 'page' 值为 apiPage (0-indexed)
后端接收到0-indexed页码
并正确查询数据 👍

🧐 代码细节剖析:转换的艺术

让我们深入 StockTotalTable.vue 的代码,看看魔法是如何发生的:

1. listQuery 的初始化:用户友好的1-indexed

// StockTotalTable.vue
private listQuery: ListQuery = {
  page: 1, // 用户看到的和组件内部维护的是第1页
  size: 15,
  total: 0, // total通常由后端返回更新
  field: 'orderNo',
  value: ''
};

这里,listQuery.page 初始化为 1。这符合很多UI组件和用户对“第一页”的直观理解。

2. getList() 方法:API调用前的关键转换 🪄

这是整个处理的核心所在:

// StockTotalTable.vue
private async getList() {
  if (!this.consignmentSettlementId) {
    this.$message.error('未找到有效的寄售单信息');
    return;
  }

  this.loading = true;
  try {
    // 👇👇👇 看这里!看这里!看这里! 👇👇👇
    const paramsForApi = {
      page: this.listQuery.page - 1, // 将1-indexed转换为0-indexed
      size: this.listQuery.size,
      field: this.listQuery.field,
      value: this.listQuery.value
    };
    console.log("实际发送给API的参数:", paramsForApi); // 建议添加日志确认

    const res = await listConsignmentSummaryByPageWithSearch(
      this.consignmentSettlementId,
      paramsForApi // 使用转换后的参数
    );

    if (res?.code === 0) {
      this.list = res.data.content;
      this.listQuery.total = res.data.totalElements; // 更新总数
    } else {
      this.$message.error(res?.message || '获取列表失败');
    }
  } catch (error) {
    console.error('获取列表失败:', error);
    this.$message.error('获取列表失败');
  } finally {
    this.loading = false;
  }
}

getList 方法内部,当准备调用 listConsignmentSummaryByPageWithSearch 这个API函数时,它创建了一个新的参数对象 paramsForApi。在这个对象中,page 的值被明确设置为 this.listQuery.page - 1

  • 初始加载/搜索时this.listQuery.page1,所以 paramsForApi.page1 - 1 = 0
  • 用户通过分页组件点击第二页handleChangePage 会将 this.listQuery.page 更新为 2。当 getList 被调用时,paramsForApi.page2 - 1 = 1

这样,无论组件内部 listQuery.page 如何表示用户当前的页码(1-indexed),最终发送到后端的 HTTP (HyperText Transfer Protocol, 超文本传输协议) 请求体中的 page 字段始终是后端 Spring Data JPA (Java Persistence API, Java持久化应用程序接口) 所期望的 0-indexed 值。

3. 分页组件交互:handleChangePage

// StockTotalTable.vue
private handleChangePage(page: number) { // page from el-pagination is 1-indexed
  this.listQuery.page = page; // 更新内部状态为用户点击的页码 (1-indexed)
  this.getList(); // 调用 getList,内部会进行 -1 转换
}

Element UI 的 el-pagination 组件在 @current-change 事件中传递的 page 是 1-indexed 的。handleChangePage 方法将这个值赋给 this.listQuery.page,保持了组件内部状态与用户视角的一致性。随后调用的 getList() 方法会负责进行必要的 -1 转换。

📊 时序图:一次成功的“页码翻译”之旅

让我们看看当用户请求(或组件初始加载)第一页数据时,这个组件是如何与后端API交互的:

用户/组件初始化"StockTotalTable.vue""api/consignment-settlement.ts""后端控制器""后端服务层"初始加载 (listQuery.page = 1)调用 this.getList()计算API参数: apiPage = listQuery.page - 1 (结果为 0)listConsignmentSummaryByPageWithSearch(id, {page: 0, ...})POST /api/.../listConsignmentSummaryByPageWithSearch Request Body: { "page": 0, ... }findSummaries(id, pageWithSearch) (pageWithSearch.page = 0)PageRequest.of(0, size, sort)后端使用0-indexed页码查询返回 Page 对象 (含数据)HTTP 200 OK Response Body: { data: { content: [...], totalElements: N } }Promise resolves with response更新 this.list 和 this.listQuery.total用户/组件初始化"StockTotalTable.vue""api/consignment-settlement.ts""后端控制器""后端服务层"

🧠 思维导图总结 (Markdown Format)

在这里插入图片描述

💡 总结:小转换,大作用!

StockTotalTable.vue 的成功之处在于它清晰地分离了两个概念:

  1. 组件内部/用户视角的页码 (this.listQuery.page):可以保持为用户更习惯的 1-indexed。
  2. 发送给后端API的页码:在调用API函数(如 listConsignmentSummaryByPageWithSearch)并构建实际的HTTP请求体时,显式地将1-indexed页码减1,转换为0-indexed

这种在“边界处”(即API调用前)进行数据转换的策略,既保证了组件内部逻辑的直观性,又满足了后端接口的特定要求。它避免了将后端特定的索引逻辑渗透到前端组件状态的每一处,使得代码更加清晰和易于维护。

所以,下次再遇到分页问题,不妨检查一下,是不是一个小小的 page - 1 就能化腐朽为神奇呢?😉 希望这个案例能给大家带来启发!


英文缩写对照表:

  • API: Application Programming Interface (应用程序编程接口)
  • SQL: Structured Query Language (结构化查询语言)
  • JPA: Java Persistence API (Java持久化应用程序接口)
  • DB: Database (数据库)
  • UI: User Interface (用户界面)
  • URL: Uniform Resource Locator (统一资源定位符)
  • HTTP: HyperText Transfer Protocol (超文本传输协议)
  • JSON: JavaScript Object Notation (JavaScript对象表示法)
  • MVC: Model-View-Controller (模型-视图-控制器架构模式)
  • AOP: Aspect-Oriented Programming (面向切面编程)
  • RLS: Row-Level Security (行级别安全)
  • VPD: Virtual Private Database (虚拟专用数据库)
  • JDBC: Java Database Connectivity (Java数据库连接)
  • DTO: Data Transfer Object (数据传输对象)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值