场景一
某一天,后端开发同事说:这个列表的数据不是特别多,我一次传给你,你自己处理一下这些数据,OK不OK?
场景二
项目经理:项目这里要做个列表页,不单独开发接口了,实现一下查询的功能就可以了。
大头答:有获取数据的接口吗?模糊查询还是精确查询?查询条件是多选还是单选?用UI组件库吗?
项目经理答:数据纯手工造,模糊查询嘛,一个或多个查询都可以晒!不合适。
······
细想片刻,我擦,还有分页要做?
捋捋思路,不用Element-UI组件库是吧?要实现列表页,主要就是实现分页以及查询噶,根据页码、是否查询来动态渲染页面数据,应该不是太难,好,开干!
需求分析
列表分页倒是没有什么太大的问题,根据设置的当前页大小拆分这个数组返回相对应的数组就行,引入查询之后呢?区别无非在于拆分的这个数组有所变化对吧,这是根据查询生成的一个新的数组,其他按部就班的来就没问题了。
参考Element-UI列表和分页的实现,通常,我们是将当前页、页面大小、查询条件一起返回后端,页面响应对应的数据就完成了。因此,这里我们可以封装一个方法就能实现这一需求,对吧!
功能实现
分页
分页一般来说,主要包括:上下页切换的功能、点击页码跳转某一页的功能以及直达某一页的功能,那目标就是正确的显示当前页的数据以及分页中的页码及其他数据,然后再注意一些其他的细节就可以了。
-
创建对应的html结构
html<div class="list_page"> <span class="page_prev" id="page_prev"> <a>上一页</a> </span> <span class="page_next" id="page_next"> <a>下一页</a> </span> <span class="page_text">跳转到</span> <span class="gopage"> <input type="text" value="1" id="gopage" name="gopage"> </span> <span class="list_page_span">GO</span> </div> </div>
为啥没有页码?查询和不查询的页码肯定是分情况讨论的啊,所以页码由我们动态生成DOM去实现;
-
生成页码及表格页面
-
确定分页大小、总页数
javascript<script> // 页面大小为15条,获取总页数 window.totalPage = Math.ceil(pageData.length / 15) <script>
-
获取对应分页上的数据
javascript<script> // 先获取当前页第一条数据和最后一条数据角码,进而分割字符串 var startIndex = (pageIndex - 1) * 15; var endIndex = startIndex + 15; var tableData = pageData.slice(startIndex, endIndex) <script>
-
页面数据渲染
渲染数据的时候,咱是否应该处理掉当前页面上的表格数据,因此,首先清空表格里面原有的数据;之后给定表头的列表数据;然后我们就来循环渲染上面我们获取到的
tableData
;因为我这里的需求是表格是斑马条纹的样式,因此这里做了一个判断,进而得到奇数和偶数两个不同属性的数据;最后填充表格数据,就完成了表格对应的页面。javascript<script> // 先获取当前页第一条数据和最后一条数据角码,进而分割字符串 const table = document.getElementById("txl_table") table.innerHTML = '' var tableHtml = '<tr><th scope="col" style="width: 348px;">商品名称</th><th scope="col" style="width: 287px;">所属品类</th><th scope="col" style="width: 465px;">订购电话</th></tr>' for (let i = 0; i < tableData.length; i++) { if (i % 2 === 0) { tableHtml += '<tr>' + '<td align="center">' + tableData[i].unitName + '</td><td align = "center" > ' + tableData[i].jobIDName + '</td><td align="center">' + tableData[i].telephone + '</td>' + '</tr>' } else { tableHtml += '<tr class="even">' + '<td align="center">' + tableData[i].unitName + '</td><td align = "center" > ' + tableData[i].jobIDName + '</td><td align="center">' + tableData[i].telephone + '</td>' + '</tr>' } } table.innerHTML = tableHtml // 给页面直达的span标签赋值,也相当于是显示第几页 document.getElementById('gopage').value = pageIndex <script>
-
分页数据的渲染
这里特别说明一下分页数据的渲染:假定我们有200条数据,分页大小为15,那么我们就有14页的数据,页码都要展示出来吗?那肯定是不需要的,展示五个页码就比较合适(如果对当前页页码有样式处理,奇数最为合适),当前页居中,对吧?如果是第九页,那我们就展示第七页、第八页、第九页、第十页、第十一页;第一页的话,就是一到五;第二页的话,也是一到五,因为没有-1页;第三页,也是一到五,且刚好居中满足我们的需求;以此类推,到第十二页的时候,对应的就是十到十四页对吧;再然后呢?为满足咱们的需求,第十三页和第十四页是不是应该只能往前推了呢,即十到十四。因此这里就是三种情况了,因此在渲染分页页面的时候就需要进行相应的一个判断;不过这里还有一种情况我们没有考虑到,如果一共就一页或者两页数据呢?这里即又是一种新的情况。
因此,实现分页的时候,我们还要考虑四种情况。
-
调用同一个方法,因此,每次渲染对应数据的时候,我们应先清空之前的页面数据;
javascript<script> // 查找页面上所有ID为"makeSpan"的span标签,然后删除 var spanElements = document.querySelectorAll('#makeSpan'); if (spanElements.length > 0) { spanElements.forEach(function (element) { element.remove(); }); } pageIndexHtmls = '' </script>
-
判断并创建对应的分页页面结构
判断的时候,我们始终会对是否为当前页进行一个判断,为减少重复代码,这里封装了一个公共的方法去判断是否为当前页,是,我们就加上"active"的属性值,否,则不添加;
javascript<script> // 是否为当前页 function generatePageIndexHtml(x, pageIndex) { var pageIndexHtml = '' if (x == pageIndex) { pageIndexHtml += '<span class="active" id="makeSpan" onclick="makePage(checkInputValues(), ' + x + ')">' + x + '</span>'; } else { pageIndexHtml += '<span id="makeSpan" onclick="makePage(checkInputValues(), ' + x + ')">' + x + '</span>'; } return pageIndexHtml; } </script>
javascript<script> if(totalPage >= 3) { if(totalPage - 2 >= pageIndex && pageIndex > 3) { for (let x = pageIndex - 2; x <= pageIndex + 2; x++) { pageIndexHtmls += generatePageIndexHtml(x, pageIndex) } } if(pageIndex > totalPage - 2) { for (let x = totalPage - 4; x <= totalPage; x++) { pageIndexHtmls += generatePageIndexHtml(x, pageIndex) } } if(pageIndex <= 3) { for (let x = 1; x <= 5; x++) { pageIndexHtmls += generatePageIndexHtml(x, pageIndex) } } } else { for (let x = 1; x <= totalPage; x++) { pageIndexHtmls += generatePageIndexHtml(x, pageIndex) } } // 在id为page_prev的span标签后添加这段html结构,即切换至上一页的按钮后添加 document.getElementById('page_prev').insertAdjacentHTML('afterend', pageIndexHtmls); </script>
-
-
-
上一页及下一页
通过监听上一页和下一页是否有点击事件来实现,如果当前页不是第一页,则上一页即自减;反之,下一页也亦是如此;
javascript<script> document.getElementById('page_prev').addEventListener('click', function () { // 获取当前页码 let currentPage = document.getElementById('gopage').value; if (currentPage > 1) { currentPage--; // makePage()是创建页面的方法,checkInputValues()是判断是否是查询的方法,后面会提到 makePage(checkInputValues(), currentPage) } }); document.getElementById('page_next').addEventListener('click', function () { let currentPage = document.getElementById('gopage').value; if (currentPage < totalPage) { currentPage++; makePage(checkInputValues(), currentPage) } }); </script>
-
点击页码跳转
因为我们在创建页面结构的时候,给每一个页面加上了对应的点击事件,即
onclick="makePage(checkInputValues(), ' + x + ')"
,这里就不用进行其他的数据处理了; -
页码直达
在前面,我们给定了一个跳转的标签,即
<span class="list_page_span">GO</span>
,在这里,我们定义一个方法,获取元素的值,从而创建对应的页面,即实现跳转直达某页的需求;这里还可以进行一些细节上的处理,比如说,用户没有输入的时候,点击这里,即仍是刷新当前页的数据,就应该禁用,在这段js代码中加上一个判断就可以了。javascript<script> function goToPage() { toPage = document.getElementById('gopage').value; makePage(checkInputValues(), Number(toPage)) } </script>
查询
在前面的分析中,我们可以知道,查询的数组就是未查询的分页数组过滤之后的新数组,之后创建页面的逻辑也是一样,因此在整体封装创建页面的方法之前,我们可以添加一个字段去判断是否进行了查询,是,就用新数组,否,就用原始的数组。
-
创建三个查询条件的输入框,即查询搜索的页面结构;
html<table width="100%" cellspacing="0" cellpadding="0" border="0" class="tablelists topfrom"> <tbody> <tr> <th>商品名称:</th> <td class="pa_l_10"><input type="text" value="" name="SearchKey" id="unitName" class="input2"></td> <th>所属品类: </th> <td class="pa_l_10"><input type="text" value="" name="SearchKey" id="jobIDName" class="input2"></td> <th>订购电话: </th> <td class="pa_l_10"><input type="text" value="" name="SearchKey" id="telephone" class="input2"></td> <td style="text-align: center;"><input type="submit" value="搜索" class="btn_submit" onclick="makePage(checkInputValues(), 1)" /></td> </tr> </tbody> </table>
-
是否查询
javascript<script> // 获取输入框是否有值,有的话,就返回true function checkInputValues() { const unitName = document.getElementById('unitName').value; const jobIDName = document.getElementById('jobIDName').value; const telephone = document.getElementById('telephone').value; var hasValues = [unitName, jobIDName, telephone].some(function (value) { return value !== ''; }); return hasValues; } </script>
-
模糊查询(过滤数组)
javascript<script> const unitName = document.getElementById('unitName').value; const jobIDName = document.getElementById('jobIDName').value; const telephone = document.getElementById('telephone').value; const result = array.filter(item => { return (item.unitName.includes(unitName) && item.jobIDName.includes(jobIDName) && item.telephone.includes(telephone)); }); // 赋值给表格数据 pageData = result </script>
拓展
搜索优化
当前实现的搜索功能是通过传入参数点击搜索实现的,单点击页面好像有点呆,想高级一点,或者说至少加上回车键入搜索吧,不难,事件传入方法即可实现;模拟远程检索(假装数据的动态的),可以吗?动态监听输入框是否有变化,调用setTimeout()方法,设置0.5秒后,触发创建页面的方法就可以了。
javascript
<script>
// 动态监听查询条件的变化
function handleValueChange() {
setTimeout(makePage(checkInputValues(), 1), 500);
}
document.getElementById('unitName').addEventListener('input', handleValueChange);
document.getElementById('jobIDName').addEventListener('input', handleValueChange);
document.getElementById('telephone').addEventListener('input', handleValueChange);
</script>
完整代码
javascript
// 表格样式
<style>
.txl_table{ margin-top:20px;}
.txl_table th{ background:#015fa7; height:40px; text-align:center; color:#fff; font-weight:normal; line-height:40px;}
.txl_table td{ height:40px; line-height:40px;}
.txl_table tr.odd{ background:#eef6fc;}
.txl_table tr.even{ background:#eef6fc;}
.txl_table tr td{ padding-left:10px;}
.txl_table tr:hover{ background:#e1effa;}
</style>
<script>
// 判断是否为当前页,同时创建分页的页面数据
function generatePageIndexHtml(x, pageIndex) {
var pageIndexHtml = ''
if (x == pageIndex) {
pageIndexHtml += '<span class="active" id="makeSpan" onclick="makePage(checkInputValues(), ' + x + ')">' + x + '</span>';
} else {
pageIndexHtml += '<span id="makeSpan" onclick="makePage(checkInputValues(), ' + x + ')">' + x + '</span>';
}
return pageIndexHtml;
}
</script>
<script>
// 创建页面
function makePage(isSearch, pageIndex) {
// 初始化将要渲染的页面数据
pageData = []
// 判断是否在进行查询,根据情况为页面原始数据赋值
if (isSearch) {
const unitName = document.getElementById('unitName').value;
const jobIDName = document.getElementById('jobIDName').value;
const telephone = document.getElementById('telephone').value;
const result = array.filter(item => {
return (item.unitName.includes(unitName) && item.jobIDName.includes(jobIDName) &&
item.telephone.includes(telephone));
});
pageData = result
} else {
pageData = array
}
// 创建分页
window.totalPage = Math.ceil(pageData.length / 15)
var spanElements = document.querySelectorAll('#makeSpan');
if (spanElements.length > 0) {
spanElements.forEach(function (element) {
element.remove();
});
}
pageIndexHtmls = ''
if(totalPage >= 3) {
if(totalPage - 2 >= pageIndex && pageIndex > 3) {
for (let x = pageIndex - 2; x <= pageIndex + 2; x++) {
pageIndexHtmls += generatePageIndexHtml(x, pageIndex)
}
}
if(pageIndex > totalPage - 2) {
for (let x = totalPage - 4; x <= totalPage; x++) {
pageIndexHtmls += generatePageIndexHtml(x, pageIndex)
}
}
if(pageIndex <= 3) {
for (let x = 1; x <= 5; x++) {
pageIndexHtmls += generatePageIndexHtml(x, pageIndex)
}
}
} else {
for (let x = 1; x <= totalPage; x++) {
pageIndexHtmls += generatePageIndexHtml(x, pageIndex)
}
}
document.getElementById('page_prev').insertAdjacentHTML('afterend', pageIndexHtmls);
// 创建列表数据
var startIndex = (pageIndex - 1) * 15;
var endIndex = startIndex + 15;
var tableData = pageData.slice(startIndex, endIndex)
const table = document.getElementById("txl_table")
table.innerHTML = ''
var tableHtml = '<tr><th scope="col" style="width: 348px;">商品名称</th><th scope="col" style="width: 287px;">所属品类</th><th scope="col" style="width: 465px;">订购电话</th></tr>'
for (i = 0; i < tableData.length; i++) {
if (i % 2 === 0) {
tableHtml += '<tr>' + '<td align="center">' + tableData[i].unitName + '</td><td align = "center" > ' +
tableData[i].jobIDName + '</td><td align="center">' + tableData[i].telephone + '</td>' + '</tr>'
} else {
tableHtml += '<tr class="even">' + '<td align="center">' + tableData[i].unitName +
'</td><td align = "center" > ' + tableData[i].jobIDName + '</td><td align="center">' + tableData[i]
.telephone + '</td>' + '</tr>'
}
}
table.innerHTML = tableHtml
document.getElementById('gopage').value = pageIndex
}
</script>
<script>
// 判断用户是否在进行查询的方法
function checkInputValues() {
const unitName = document.getElementById('unitName').value;
const jobIDName = document.getElementById('jobIDName').value;
const telephone = document.getElementById('telephone').value;
var hasValues = [unitName, jobIDName, telephone].some(function (value) {
return value !== '';
});
return hasValues;
}
</script>
<script>
// 初始化页面
let array = [
{ unitName: '苹果', jobIDName: '水果', telephone: '028-12345678' },
······
{ unitName: '电烤箱', jobIDName: '家电', telephone: '028-87654321' }
]
makePage(checkInputValues(), 1)
</script>
<script>
// 监听上一页
document.getElementById('page_prev').addEventListener('click', function () {
let currentPage = document.getElementById('gopage').value;
if (currentPage > 1) {
currentPage--;
makePage(checkInputValues(), currentPage)
}
})
// 监听下一页
document.getElementById('page_next').addEventListener('click', function () {
let currentPage = document.getElementById('gopage').value;
if (currentPage < totalPage) {
currentPage++;
makePage(checkInputValues(), currentPage)
}
})
// 直达目标页方法实现
function goToPage() {
toPage = document.getElementById('gopage').value;
makePage(checkInputValues(), Number(toPage))
}
</script>