现如今是前后端分离的天下。前端管前端的工作。后端管后端的工作,大家彼此不相干。如果开发文档写得很详细,可以说两组人“老死不相往来”都可以。
那么,在开发中,分页是一个家常便饭,每一个开发人员都会遇上。从古以来,处理分页都有两种方案,一种是前端处理,另一种就是后端处理。(主要看下面红框的三个部份)
前端处理,其实就是后端只需要返回一个所有的数组集合给前端。而前端只需要拿到这个集合做分页处理就行。
<!--前面的filter 想必大家都知道,是在表格中搜索的-->
<!--而 slice 则是分页 ,这儿我大概先说下各参数的用法-->
<!--slice函数,想必大家都清楚是数组截取的方法。大概可以这样去理解,从第几条开始,截多少条数据-->
<!--(currentPage - 1) * pagesize 第几页 * 每页多少条数据 (因为默认是从第一页开始的,而数据是从零开始,所以才会 当前码减1的说法)-->
<!--打个比方,假如当前是第一页,一页10条 ,那么就是 【(1-1)* 10】 也就是从数组的第0个开始截取-->
<!--currentPage * pagesize 当前页 * 1页多少条-->
<!--继续上页的那个比方,刚说了,从数组的第零个开始,截取 【当前页为第1页 * 一页10条】-->
<!--那么,我点击第2页的时候呢? 就是 第2页是当前页了-->
<!--所以,根据公式 【(当前页2 - 1) * 每一页 10条】也就是从第10条开始截取,到 【(当前页2 * 第页10条)】-->
<el-table
:data="tableData.filter(data => !search || data.title.toLowerCase().includes(search.toLowerCase())).slice((currentPage - 1) * pagesize , currentPage * pagesize)"
style="width: 100%">
<el-table-column label="Date" prop="id"></el-table-column>
<el-table-column label="title" prop="title"></el-table-column>
<el-table-column label="pro" prop="pro"></el-table-column>
<el-table-column align="right">
<!-- eslint-disable-next-line vue/no-unused-vars -->
<template slot="header" slot-scope="scope">
<el-input v-model="search" size="mini" placeholder="输入关键字搜索"/>
</template>
<template slot-scope="scope">
<el-button size="mini" @click="edit(scope.row.id)">Edit</el-button>
<el-button size="mini" type="danger" @click="del(scope.row.id)">Delete</el-button>
</template>
</el-table-column>
</el-table>
<!--@size-change 选择下拉框后触发的事件,下拉框的内容就是说 一页有几条数据的意思-->
<!--layout 就是那分页条的布局,从左到右依次是 总数、下拉框、前一页、页码、后一页、直接到哪一页 (而这些字符串是固定的,不能修改,如果哪个不想显示,可以不填写)-->
<!--:total 总数,也就是直接从后端查出来的总数,它是一个整型-->
<!--:page-sizes 下拉框,也就是可以让用户自己选择一页有多少条数据,它是一个数组-->
<!--@current-change 触发页面的函数,也就是 比如说我点击 第3页,那它的页码就会是3-->
<!--:page-size 页面一加载,默认的 一页显示多少条数据-->
<div style="text-align: right">
<el-pagination background
@size-change="handleSizeChange"
layout="total,sizes,prev, pager, next , jumper"
:total="fontData.total"
:page-sizes="[1,2, 3, 10, 30, 50, 80, 100]"
@current-change="handleCurrentChange"
:page-size="pagesize">
</el-pagination>
</div>
data(){
return {
currentPage: 1, //当前页,点击页码时改变的就是这个值
pagesize: 10, //一页有多少条数据
tableData:[], //后台给的数据,是一个集合
search:'', //在表格中搜索框的邦定数据,是一个字符串
}
},
methods:{
handleSizeChange(pagesize){//选择下拉时触发
this.pagesize = pagesize //触发该方法后,需要改变
},
handleCurrentChange(size){ //点击页码时触发
this.currentPage = size; 触发该方法后,需要改变
},
getList(){//请求后端拿数据的方法
//this.fontData 是请求的参数,比如说做搜索的时候,可能会用上
getList(this.fontData)
.then(res=>{
let data = res.data.list;
this.tableData = data;
this.fontData.total = res.data.len
})
},
}
而后端分页,就是前端把【每一页多少条,页码】传给后端,后端去做分页处理。也就是说,前端只需要传这两个参数就可以实现分页。
<el-table :data="tableData.filter(data => !search || data.title.toLowerCase().includes(search.toLowerCase()))" style="width: 100%">
<el-table-column label="Date" prop="id"></el-table-column>
<el-table-column label="title" prop="title"></el-table-column>
<el-table-column label="pro" prop="pro"></el-table-column>
<el-table-column align="right">
<!-- eslint-disable-next-line vue/no-unused-vars -->
<template slot="header" slot-scope="scope">
<el-input v-model="search" size="mini" placeholder="输入关键字搜索"/>
</template>
<template slot-scope="scope">
<el-button size="mini" @click="edit(scope.row.id)">Edit</el-button>
<el-button size="mini" type="danger" @click="del(scope.row.id)">Delete</el-button>
</template>
</el-table-column>
</el-table>
<!--这儿的参数我就不再估介绍了,跟上面前端分页是一样的-->
<div style="text-align: right">
<el-pagination background
@size-change="handleSizeChange"
layout="total,sizes,prev, pager, next"
:total="fontData.total"
:page-sizes="[2, 3, 10, 30, 50, 80, 100]"
@current-change="handleCurrentChange"
:page-size="fontData.pagesize">
</el-pagination>
</div>
data(){
return {
fontData:{
total: 0, //总条目数
pagesize: 10, //每页显示条目个数
page: 1, //页面加载完显示的默认页的页码
},
tableData:[],
search:'',
}
},
methods:{
handleSizeChange(pagesize){//选择下拉时触发
this.fontData.pagesize = pagesize;
this.getList();//注意这儿,需求再次执行请求数据的方法,因为是每点一次,它都会从后端拿一部份数据
},
handleCurrentChange(size){ //点击页码时触发
this.fontData.page = size;
this.getList(); //注意这儿,需求再次执行请求数据的方法,因为是每点一次,它都会从后端拿一部份数据
},
getList(){ //请求的数据
getList(this.fontData)
.then(res=>{
let data = res.data.list;
this.tableData = data;
this.fontData.total = res.data.len
})
},
}
最后,我附上一段php的分页代码(php是基于tp6的,大家可以拿来做参考)
<?php
namespace app\common\model;
use think\Model;
use think\facade\Db;
class XbMeeting extends Model{
static public function getList($where,$page = null){
if($page){//如果一条多少条最在,那么,它就走的是后端分页的逻辑
$list = Db::name('xb_meeting')
->where($where)
->paginate([
'list_rows' => $page,
'query' => request()->param(),
]);
return $list;
}
$list = Db::name('xb_meeting')->where($where)->select();
return $list;
}
?>
<?php
namespace app\php\controller\xiaobing;
use app\BaseController;
use app\common\model\XbMeeting;
class Test extends BaseController{
private $xbMeeting;
public function __construct(XbMeeting $xbMeeting){
$this->xbMeeting = $xbMeeting;
}
public function search(){
$array = array();
if(isset($_GET['title'])){
$array[] = ['title','like' , '%'. input('get.title') .'%'];
}
if(isset($_GET['content'])){
$array[] = ['content','like' , '%'. input('get.content') .'%'];
}
return $array;
}
public function index(){
$where = $this->search();
$where[] = ['isDel', '=' ,0];
//也就是说,上面模型中,判断有没有后端分页的逻辑就看 pagesize 变量是否有值,如果没有那它就不走后端分页的代码。
//或者说,如果 $pagesize 没有值,前端拿到的是所有的数据,那它要做分页,只是是他前端做分页。
$pagesize = input('get.pagesize');
$list = $this->xbMeeting::getList($where,$pagesize);
if($pagesize){
$count = $list->total();
$data_list = $list->items();
$page = $list->render();
$res = array(
'code' => 200,
'message' => 'success',
'data' => ['list'=>$data_list,'len'=>$count]
);
return json($res,200);
}
return $list;
}
?>
其实,总的来说的话,不管是前端做分页还是后端做分页。其原理都是大同小异的。而且,不管哪种方法,都存在他们各自的利和弊。
前端做分页,它只需要在第一次的时候拿数据,之后它都不再后端。而如果说数据量大的话,拿数据的时间会长一些。
后端做分页,它就是每一次获取数据都需要走一次后端。当然,这走后端拿的数据只是很小的一部份。
当然,不管是前端还是后端,在必要的时候,数据库是需要做些优化或者是索引,这样才能达到更高效率的效果。