news 2026/4/18 11:28:36

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/17 13:58:24

发现并分析PHP木马后门代码

发现并分析PHP木马后门代码 在当今AI基础设施快速部署的背景下&#xff0c;一个看似不起眼的文件上传漏洞&#xff0c;可能就是整条攻击链的起点。比如当你在服务器上为 Z-Image-ComfyUI 添加一个“自定义节点脚本”时&#xff0c;如果未对上传内容做严格校验&#xff0c;攻击者…

作者头像 李华
网站建设 2026/4/18 5:42:40

【电力】3D空间桁架电力传输塔FEM分析附Matlab代码

✅作者简介&#xff1a;热爱科研的Matlab仿真开发者&#xff0c;擅长数据处理、建模仿真、程序设计、完整代码获取、论文复现及科研仿真。&#x1f34e; 往期回顾关注个人主页&#xff1a;Matlab科研工作室&#x1f34a;个人信条&#xff1a;格物致知,完整Matlab代码及仿真咨询…

作者头像 李华
网站建设 2026/4/18 7:05:40

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

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

作者头像 李华
网站建设 2026/4/18 7:03:08

【scala】匿名函数和高阶函数

package com.hdfs.functaionobject Anonymous {def main(args: Array[String]): Unit {AnonymousFunctionprintln(normalcalc(2, 3, 4))println(curriedCalc(2)(3)(4))println(curriedCalcee(2)(3)(4))}def AnonymousFunction(): Unit {/*** 匿名函数&#xff0c;函数字面量&…

作者头像 李华
网站建设 2026/4/18 7:32:18

从加密文件中还原WebShell代码的全过程

从加密文件中还原WebShell代码的全过程 最近在排查一台服务器异常行为时&#xff0c;偶然发现了一个极其隐蔽的后门。事情的起点是一条不起眼的日志记录。 当时我正例行检查 Nginx 的访问日志&#xff0c;突然注意到一条路径&#xff1a; GET /uploads/images/2024/glm_decode.…

作者头像 李华