news 2026/4/15 13:30:38

Vue结合ElementUI实现分页、HTTP封装与农历转换

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Vue结合ElementUI实现分页、HTTP封装与农历转换

Vue 与 ElementUI 实现分页、HTTP 封装及农历转换的工程实践

在构建现代前端应用时,我们常常需要处理大量数据展示、统一管理接口请求,并增强用户对时间信息的理解。尤其是在政务系统、日程提醒、文化类平台等场景中,不仅要呈现公历日期,还需标注农历节日和节气,以提升本土化体验。

本文将围绕一个真实可用的技术栈组合——Vue 2 + ElementUI,深入探讨如何在一个项目中高效整合三大核心功能:
- 基于el-pagination的智能分页展示
- 使用 Axios 封装的可复用 HTTP 请求模块
- 支持节日识别的公历转农历工具

整个实现过程注重代码结构清晰、逻辑解耦与工程可维护性,适合用于中后台管理系统或内容型 Web 应用的快速开发。


当我们面对一个包含数百条文章的数据列表时,直接渲染显然不现实。更合理的做法是通过分页控制每页显示数量,既减轻浏览器负担,也提升用户体验。

ElementUI 提供了开箱即用的<el-pagination>组件,配合 Vue 的计算属性(computed),我们可以轻松实现本地分页:

<template> <div class="article-page"> <h2>技术博客列表</h2> <ul class="article-list"> <li v-for="(item, index) in paginatedList" :key="index" class="article-item"> <h3>{{ item.title }}</h3> <p>{{ item.summary }}</p> <small>发布于:{{ item.date }}</small> </li> </ul> <div class="pagination-container"> <el-pagination @current-change="handlePageChange" :current-page="currentPage" :page-size="pageSize" :total="articleList.length" layout="prev, pager, next, total" background /> </div> </div> </template> <script> export default { name: 'ArticleList', data() { return { currentPage: 1, pageSize: 8, articleList: [] } }, computed: { paginatedList() { const start = (this.currentPage - 1) * this.pageSize; const end = start + this.pageSize; return this.articleList.slice(start, end); } }, methods: { handlePageChange(page) { this.currentPage = page; } }, mounted() { this.fetchArticles(); } } </script>

这里的paginatedList是典型的计算属性用法:它依赖currentPagepageSize自动响应式更新,无需手动触发重计算。当用户点击页码时,@current-change回调更新当前页,视图随之刷新。

值得注意的是,这种模式适用于前端已有完整数据的情况。若后端支持分页查询,建议改为传递page参数到 API,减少网络传输量。


为了统一管理所有 API 调用,避免重复编写请求头、错误处理逻辑,封装一个全局 HTTP 工具是必要的工程实践。

我们基于 Axios 创建src/utils/request.js,并加入拦截器机制,实现权限认证与异常统一处理:

import axios from 'axios' const service = axios.create({ baseURL: process.env.NODE_ENV === 'production' ? 'https://api.example.com' : '/api', timeout: 10000, headers: { 'Content-Type': 'application/json' } }) // 请求拦截:添加 token service.interceptors.request.use( config => { const token = localStorage.getItem('token') if (token) { config.headers['Authorization'] = `Bearer ${token}` } return config }, error => { console.error('Request Error:', error) return Promise.reject(error) } ) // 响应拦截:统一错误提示 service.interceptors.response.use( response => { const res = response.data if (res.code !== 200 && res.code !== undefined) { alert(`Error: ${res.message || '未知错误'}`) return Promise.reject(new Error(res.message || 'Error')) } return res }, error => { if (error.response) { switch (error.response.status) { case 401: alert('未授权,请登录') break case 404: alert('请求资源不存在') break default: alert('网络异常') } } return Promise.reject(error) } ) export default service

这个封装带来的好处非常明显:

  • 环境适配:根据NODE_ENV切换基础 URL,开发调试更方便;
  • 安全加固:自动携带 Token,防止未授权访问;
  • 错误集中处理:无论是业务码非 200 还是 HTTP 状态码异常,都能及时反馈给用户;
  • 易于扩展:后续可加入 loading 拦截、缓存策略、重试机制等。

在组件中使用也非常简洁:

import request from '@/utils/request' export default { methods: { async fetchArticles() { try { const res = await request({ url: '/articles', method: 'get' }) this.articleList = res.data || [] } catch (err) { this.articleList = [] } } } }

一行调用即可完成带拦截、鉴权、错误处理的请求,极大提升了开发效率。


传统节日和二十四节气在中国文化中具有重要意义。在日历类应用中仅显示公历显然不够友好。为此,我们需要将公历日期转换为农历,并标注节日与节气。

我们创建src/utils/calendar.js,引入轻量级农历算法库(适用于 1900–2100 年):

const calendar = { lunarInfo: [ 0x04bd8, 0x04ae0, 0x0a570, 0x054d5, 0x0d260, 0x0d950, 0x16554, 0x056a0, 0x09ad0, 0x055d2, // ... 中间省略,实际项目请补全全部数据 ], solarTerm: [ "小寒","大寒","立春","雨水","惊蛰","春分","清明","谷雨", "立夏","小满","芒种","夏至","小暑","大暑","立秋","处暑", "白露","秋分","寒露","霜降","立冬","小雪","大雪","冬至" ], festival: { "1-1": { title: "元旦" }, "5-1": { title: "劳动节" }, "10-1": { title: "国庆节" }, "12-25": { title: "圣诞节" } }, lFestival: { "1-1": { title: "春节" }, "1-15": { title: "元宵节" }, "5-5": { title: "端午节" }, "8-15": { title: "中秋节" }, "12-8": { title: "腊八节" } }, solar2lunar(solarYear, solarMonth, solarDay) { // 此处为简化示意,实际需完整实现 offset 计算、闰月判断等 const festivals = this.festival[`${solarMonth}-${solarDay}`] return { IDayCn: `${solarDay}`, IMonthCn: `${solarMonth}月`, festival: festivals ? festivals.title : null, Term: null, isLeap: false, Animal: ['鼠','牛','虎','兔','龙','蛇','马','羊','猴','鸡','狗','猪'][(solarYear - 4) % 12] } } } export default calendar

⚠️ 注意:完整版lunarInfo数组包含约 250 项,用于精确计算每年的农历月份天数与闰月位置。建议从开源项目如 jjonline/calendar 获取完整算法。

在 Vue 组件中集成该工具,结合el-calendar自定义单元格内容:

<template> <el-calendar v-model="currentDate"> <template #date-cell="{data}"> <div @click="onDateClick(data)"> <span class="day">{{ data.day.split('-')[2] }}</span> <div class="lunar-info" :class="{ 'holiday': isHoliday(data) }"> {{ getLunarText(data) }} </div> </div> </template> </el-calendar> </template> <script> import calendar from '@/utils/calendar' export default { data() { return { currentDate: new Date() } }, methods: { onDateClick(data) { console.log('Clicked date:', data.day) }, getLunarText(data) { const [y, m, d] = data.day.split('-').map(Number) const lunar = calendar.solar2lunar(y, m, d) if (lunar.festival) return lunar.festival if (lunar.Term) return lunar.Term return lunar.IMonthCn + lunar.IDayCn }, isHoliday(data) { const [y, m, d] = data.day.split('-').map(Number) const lunar = calendar.solar2lunar(y, m, d) return !!(lunar.festival || lunar.Term) } } } </script> <style scoped> .el-calendar ::v-deep .el-calendar-day { height: 100px; display: flex; flex-direction: column; justify-content: center; align-items: center; } .day { font-size: 14px; font-weight: bold; } .lunar-info { font-size: 11px; color: #999; margin-top: 4px; } .holiday { color: #f56c6c !important; font-weight: bold; } </style>

效果上,每一天都会显示对应的农历信息,节日或节气则以红色高亮,视觉区分明显,用户一眼即可识别重要日子。


最终,我们将三个模块融合成一个完整的仪表盘页面,左侧展示分页文章列表,右侧嵌入农历日历:

<!-- ArticleWithCalendar.vue --> <template> <div class="dashboard"> <h1>技术文章与日历系统</h1> <div class="content-area"> <!-- 左侧文章列表 --> <section class="articles"> <h2>最新文章</h2> <ul class="article-list"> <li v-for="(art, idx) in paginatedList" :key="idx"> <router-link :to="'/article/' + art.id"> {{ art.title }} <em>{{ art.date }}</em> </router-link> </li> </ul> <el-pagination @current-change="handlePageChange" :current-page="currentPage" :page-size="8" :total="articleList.length" layout="prev, pager, next, total" /> </section> <!-- 右侧日历 --> <section class="calendar-section"> <el-calendar v-model="today"> <template #date-cell="{data}"> <div> <span>{{ data.day.split('-')[2] }}</span> <div class="lunar-tip" :class="{fest: isFestival(data)}"> {{ lunarLabel(data) }} </div> </div> </template> </el-calendar> </section> </div> </div> </template> <script> import request from '@/utils/request' import calendar from '@/utils/calendar' export default { data() { return { currentPage: 1, articleList: [], today: new Date() } }, computed: { paginatedList() { const start = (this.currentPage - 1) * 8 return this.articleList.slice(start, start + 8) } }, methods: { handlePageChange(page) { this.currentPage = page }, async fetchArticles() { try { const res = await request.get('/articles') this.articleList = res.data.map(d => ({ id: d.id, title: d.title, date: d.pub_date })) } catch (e) { this.articleList = [] } }, lunarLabel(data) { const [y, m, d] = data.day.split('-').map(Number) const lunar = calendar.solar2lunar(y, m, d) if (lunar.festival) return lunar.festival if (lunar.Term) return lunar.Term return lunar.IMonthCn + lunar.IDayCn }, isFestival(data) { const [y, m, d] = data.day.split('-').map(Number) const lunar = calendar.solar2lunar(y, m, d) return !!lunar.festival || !!lunar.Term } }, mounted() { this.fetchArticles() } } </script> <style scoped> .dashboard { max-width: 1200px; margin: 0 auto; padding: 20px; } .content-area { display: flex; gap: 30px; } .articles { flex: 1; } .calendar-section { width: 300px; } .article-list { list-style: none; padding: 0; } .article-list li { padding: 8px 0; border-bottom: 1px solid #eee; } .lunar-tip { font-size: 12px; color: #aaa; } .fest { color: #e60000; font-weight: bold; } </style>

这样的布局兼顾功能性与美观性,特别适合资讯门户、企业内网、个人博客后台等场景。


这套方案的价值不仅在于实现了具体功能,更在于其体现的工程化思维:

  • 分页设计避免一次性加载过多数据,保障性能;
  • HTTP 封装实现请求标准化,降低维护成本;
  • 农历工具提升产品文化感知力,增强用户体验。

这些模式均可独立抽离为公共模块,在多个项目中复用。例如,可将calendar打包为 NPM 包,或将请求拦截器抽象为插件形式。

未来还可进一步优化:
- 引入 Vuex 或 Pinia 管理全局状态(如当前页、用户信息);
- 使用 TypeScript 增强类型安全;
- 接入真实农历 API 提供更高精度服务;
- 支持主题切换与国际化。

前端开发不仅是“写页面”,更是构建可持续演进的系统。从一个小功能出发,思考其背后的架构意义,才能真正写出高质量、易维护的代码。


版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/13 23:13:55

【Java毕设源码分享】基于springboot+vue的实验室实验报告管理系统的设计与实现(程序+文档+代码讲解+一条龙定制)

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

作者头像 李华
网站建设 2026/4/6 14:26:02

【Java毕设源码分享】基于springboot+vue的大学生校园线上招聘系统的设计与实现(程序+文档+代码讲解+一条龙定制)

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

作者头像 李华
网站建设 2026/4/13 12:17:57

Intel NCS算力棒在Ubuntu16.04的部署指南

Intel NCS算力棒在Ubuntu16.04的部署指南 &#x1f3b5; 零样本语音克隆 情感表达 音素级控制 webUI二次开发 by 科哥 微信&#xff1a;312088415 在边缘计算和轻量化AI推理需求日益增长的今天&#xff0c;Intel Neural Compute Stick&#xff08;NCS&#xff09;作为一款低成…

作者头像 李华
网站建设 2026/4/14 8:13:05

熔融缩聚中影响线型缩聚物分子量的因素

熔融缩聚中影响线型缩聚物分子量的关键因素解析 在高分子材料合成领域&#xff0c;熔融缩聚是制备聚酯、聚酰胺和聚碳酸酯等工程塑料的核心工艺。这类反应无需溶剂&#xff0c;直接在高温熔融状态下进行&#xff0c;通过逐步缩合官能团并脱除小分子副产物&#xff08;如水、甲醇…

作者头像 李华
网站建设 2026/4/10 20:58:03

美团动态线程池,香啊!

「使用线程池 ThreadPoolExecutor 过程中你是否有以下痛点呢&#xff1f;」1.代码中创建了一个 ThreadPoolExecutor&#xff0c;但是不知道那几个核心参数设置多少比较合适2.凭经验设置参数值&#xff0c;上线后发现需要调整&#xff0c;改代码重启服务&#xff0c;非常麻烦3.线…

作者头像 李华