koa-vue的分页实现

news/2024/11/29 3:41:02/

1.引言

    最近确实体会到了前端找工作的难处,不过大家还是要稳住心态,毕竟有一些前端大神说的有道理,前端发展了近20年,诞生了很多leader级别的大神,这些大神可能都没有合适的坑位,我们新手入坑自然难一些,前端现在对于新手的高要求也能够理解,只能硬着头皮完善自我了。而且距离自己3月20找工作底线时间还有两周,同花顺和恒生电子的笔试在还进展中,实在不行真得二战我倒也不怕。闲来无聊写一篇“应用文”吧(不过最近应用文会大幅减少,毕竟讲不清楚原理才是真得凉凉)。

2.场景描述

    我们经常遇到前端列表,需要进行分页处理,一般前端会说那是后端的任务,但是其实前端也是有工作量的,后端的分页任务其实不大,如果会一点sql语句就明白了,一句sql就能够实现(当然我这里没有包括必要参数检测和优化、错误反馈、防注入等内容)。
    在实现上,对于后端而言,主要是怎么告诉前端已经没有数据了,对于前端而言怎么确定需要再次请求数据了,另外前端还需要对数据进行缓存,提高性能。

3.后端设计与实现

    后端代码如下,主要做的是前端传入参数的检测和数据是否查询完毕了。说一下思路,参数检测可以利用强制转换来判断传入的参数的类型,包括是否传入、传入的参数是否正确、请求的数据量是否合理(如果不做限制),想想select *吧。在查询结束上,我这里分了两次查询,就是额外请求一次数据库查询当前符合要求的被分页获取的数据的总数。实现的代码如下:

async function getMatchList(ctx) {let { id, page, limit } = ctx.query;//这里对分组id详细说明,由于前端页面有多个分组,所以这里多一个分组idid = Number(id).toString() == "NaN" ? 1 : Number(id);//分组信息,默认请求第一组的信息page = Number(page).toString() == "NaN" ? 1 : Number(page);//分页,默认请求第一页limit = Number(limit).toString() == "NaN" ? 5 : Number(limit);//分页,默认请求5篇let total = await countByGroup(id);//获取总数//console.log("输出请求参数", id, page, limit);await matchList(id, page, limit).then((data) => {let isTotal = limit * page >= total ? 1 : 0;sendData(ctx, {list: data,isTotal});}).catch((err) => {console.log("输出错误信息:", err);throwError(ctx, -1);});
};

    接下来贴的是与数据库交互的代码,因为我接触thinkphp6比较早,对于thinkphp6的MVC设计模式影响比较深刻,所以一般写后端会自觉将与数据库交互的内容从controller层抽离,这样代码结构也更加清晰,当然你如果喜欢使用ORM架构的话,nodejs是有一个叫Sequelize的第三方依赖包的,但是这个不是很火哈。

//这里是对数据库的连接,每请求一次连接一次数据库?
//不是的,我这里使用的是单例模式;
//构造了一个数据库连接的单例类,如果有连接实例存在直接使用,否则实例化一个数据交互类
const MysqlConnect = require("../config/connect-mysql");
const mysqlDB = new MysqlConnect();
async function countByGroup(group_id) {return new Promise((resolve, reject) => {const sql = `select count(*) sum from match_list where group_id = ${group_id}`;mysqlDB.query(sql, (err, result) => {if (err) {console.log("数据表match查询数据出错:", err);reject(err);} else {resolve(result[0].sum);}})})
}
async function matchInfo() {return new Promise((resolve, reject) => {const sql = "select id,banner,tag from match_group order by id asc";mysqlDB.query(sql, (err, result) => {if (err) {console.log("数据表match查询数据出错:", err);reject();}resolve(result);})});
}
async function matchList(group_id, page, limit) {return new Promise((resolve, reject) => {const sql = `select id,swiperList,title,detail,goods from match_list where group_id = ${group_id} order by id asc ` +`limit ${(page - 1) * limit},${limit}`;mysqlDB.query(sql, (err, result) => {if (err) {console.log("数据表match查询数据出错:", err);reject();}resolve(result);})});
}
module.exports = { matchInfo, matchList,countByGroup };

4.前端的实现与缓存

    可能大家更关心前端怎么实现的吧,前端的实现有一个关键点,就是监听滑动事件,实现上使用的是 @scroll="pageScroll",然后监听event对象里面的3个重要的属性:scrollTopclientHeightscrollHeight。解释这三个参数的含义:举例大盒子顶部的举例、用户视口可视区、具备滑动能力的盒子的总高度(在dom渲染之后这个属性可以自动更新)。

pageScroll(e) {if (e.target.scrollTop + e.target.clientHeight + 20 > e.target.scrollHeight) {//重新发送请求,获取新一批文章this.currentPage++;console.log("输出数据:", this.isTotal);if (!this.isTotal) {showLoadingToast({message: '加载中...',forbidClick: true,loadingType: 'spinner',});this.getMatchList(this.currentTabId, this.currentPage, this.limit);} else {showToast({message: '再怎么找也没有啦~',wordBreak: 'break-word'});}}}

    注意为了能够有效监听到这些参数,需要对css稍微设置一下:

.share-container {background-color: #181818;padding: 0px 10px;padding-bottom: 60px;height: calc(100vh - 90px);//底部留白设计,避免不方便阅读最下面的内容,//同时也能够增加一个没有更多的友好提示overflow: scroll;
}.share-container::-webkit-scrollbar {//这个是为了防止默认滚动条的出现影响了flex布局,直接给隐藏掉display: none;/*Safari and Chrome*/
}

    如今的前端会这些可不够,我这里展示一下期望有的功能:
在这里插入图片描述
    我这里的目标平台是h5(vantUI组件库),如果是uniapp或者小程序的话直接提供了用户滑动触底函数,更简单了,都不用自己监听。上面的效果也有一个是前端的比较常用的——吸顶式布局(position:stikcy,不细说了),在切换tab的时候可以采用缓存,每次切换之后存到localstorage里面,存储方式推荐用JSON.stringify来存,读完之后JSON.parse()转回来,你可能想说要是小程序呢,在uniapp和微信小程序都是提供了缓存读写的,可以查看对应的用法。需要注意的是,为了保证数据安全可以使用一个简单的加密解密比如crypto-js依赖(不够的话再撒点“盐”),能够防止用户直接查看你存储的信息。

5.代码优化方案

    因为我这里写的是毕设的一部分代码,可能在企业应用上看不够严谨,还有很多可以优化的,这里补充一些方案:
(1)在数据加载的时候可以使用骨架屏,因为如果是涉及到图片等加载比较慢容易出现比较严重的闪频,特别是图片内存比较大的时候;
(2)因为这里使用的是分页可滑动,“懒加载”请求出战,因为这里有滑动,“虚拟列表”请求出战;
(3)因为这里有缓存,需要考虑到缓存的有效期问题,如何刷新缓存?当然上面我使用的是切换tab的时候写缓存和读切换目标的缓存,在单纯数据追加上还是说的过去,但是如果信息被修改了就会出现不及时的情况,这里有一个不是很好的方案,全局配置,多加一个网站配置请求,决定是否使用系统缓存的变量,系统资源更新时修改提示放弃使用缓存;
(4)一般列表的图片等可以考虑CDN部署,提均衡多地区的用户体验,也就是让远离服务器的用户能够更快获得响应;
(5)这里的localstorage有些情况下不能使用,可能需要使用redis再来缓存数据,当然这是后端的任务,同时可以利用redis来对请求满足要求的列表数量总数缓存一下,减少额外查库,其实查的是同一个数据。
    最后祝各位找工作的好兄弟们加油,坚持就是顺利!


http://www.ppmy.cn/news/30376.html

相关文章

hive真实表空间大小统计

1. 问题 如果是采用hdfs上传加载的表、或者是flume直接写hdfs的表空间通常看hive的属性是不准确的。 2. 思路 为了使结果更精确,我们直接使用linux下命令统计hive仓库目录下的每个表对应的文件夹目录占用空间的大小。 3. 解决方法 这里建立三层表结构 ods: 原始…

Cadence Allegro 导出Component Pin Report详解

⏪《上一篇》   🏡《总目录》   ⏩《下一篇》 目录 1,概述2,Component Pin Report作用3,Component Pin Report示例4,Component Pin Report导出方法4.1,方法14.2,方法2B站关注“硬小二”浏览更多演示视频 <

看完这篇入门性能测试

几十万人同时进入某媒体直播间&#xff0c;造成流量激增从监控上可以看出&#xff0c;QPS到达某峰值后&#xff0c;部分进入直播间即调用的接口&#xff08;这类接口属于高并发接口&#xff0c;在短时间内承载非常高的QPS&#xff09;以及对应接口的下游&#xff0c;均出现了非…

三个案例场景带你掌握Cisco交换机VLAN互通

VLAN间路由的方式现在主流的组网主要是依靠三层交换机通过配置SVI接口【有的厂商叫VLANIF接口】&#xff0c;当然也有比较小型的网络&#xff0c;它就一个出口路由器可管理的二层交换机&#xff0c;还有一种更加差的&#xff0c;就是出口路由一个可管理的二层交换机&#xff0c…

JavaScript Math 算数对象

文章目录JavaScript Math 算数对象Math 对象Math 对象属性Math 对象方法算数值算数方法JavaScript Math 算数对象 Math&#xff08;算数&#xff09;对象的作用是&#xff1a;执行常见的算数任务。 Math 对象 Math&#xff08;算数&#xff09;对象的作用是&#xff1a;执行普…

MySQL用户管理与权限管理

一&#xff1a;用户管理 1、登录Mysql服务器 mysql –h hostname|hostIP –P port –u username –p DatabaseName –e "SQL语句" 例如&#xff1a; mysql -uroot -p -hlocalhost -P3306 mysql -e "select host,user from user" 查看所有用户 select host…

HTML常见标签

文章目录一、HTML基础标签注释标签标题标签段落标签换行标签格式化标签图片、音频、视频标签超链接标签列表标签表格标签布局标签表单标签表单标签概述form标签属性表单项标签综合案例一、HTML基础标签 基础标签就是和文字相关的标签 标签描述<h1> ~ <h6>定义标题…

【C++】位图+哈希切割+布隆过滤器

文章目录一、位图1.1 位图概念1.2 位图实现1.2.1 把x对应比特位0置11.2.2 把x对应比特位1置01.2.1 查看x对应比特位1.3 位图源码1.4 位图的应用二、哈希切割&#xff08;处理海量数据&#xff09;三、布隆过滤器3.1 布隆过滤器的概念3.2 布隆过滤器的应用场景3.3 布隆过滤器的实…