前言
近几年根本都是开发 SPA
利用,敌人找我帮忙做一个简略的后盾治理的模块,是传统的 ASP.NET
WEB
页面,不过我这次还是写独立的前端界面的,只是会基于他们零碎应用的框架去开发(jq+bootstrap
)。
工作
- 列表页(搜寻、表格展现、分页)
- 表单提交页(新增 / 编辑)
技术框架
- jQuery
- bootstrap.js(v3)
- art-template
- wdate
- …
例子:https://blog.csdn.net/weixin_…
开发笔记
原我的项目用的是
v3
版本的bootstrap
表格
原我的项目中表格有用 bootstrapTable
插件(性能看着挺齐全),因为其官网例子很多加载不进去(控制台报错),本人对它不相熟,且工作工夫紧放心用了前面要扩大不不便,我就没用它的。
表格我是申请数据后,间接用 art-template 模版引擎去渲染,简略的示例界面如下:
界面:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>art-Templat 例子 </title>
<script src="./lib/art-template/template-web.js"></script>
<style>
table {
border-collapse: collapse;
border-spacing: 0;
}
table .th {
background-color: #f5f5f5;
font-size: 12px;
font-weight: bold;
}
table tr {border-top: 1px solid #dfdfdf;}
table tr:last-child {border-bottom: 1px solid #dfdfdf;}
table tr td {
padding: 4px 6px;
font-size: 12px;
}
</style>
</head>
<body>
<!-- 列表 -->
<table class="table">
<tbody id="table-tbody">
</tbody>
</table>
<!-- 列表内容模版 -->
<script id="tpl-table-tbody" type="text/html">
<tr class="th">
<td>ID</td>
<td> 订单号 </td>
<td> 收货人 </td>
<td> 手机号 </td>
<td> 状态 </td>
<td> 创建人 </td>
<td> 创立工夫 </td>
</tr>
{{each list}}
<tr>
<td>{{$value.id}}</td>
<td>{{$value.orderNo}}</td>
<td>{{$value.receiver}}</td>
<td>{{$value.phone}}</td>
<td>{{$value.status}}</td>
<td>{{$value.creator}}</td>
<td>{{$value.createTime}}</td>
</tr>
{{/each}}
</script>
</body>
</html>
对应 JS:
var html = template('tpl-table-tbody', {
list: [{
id: 'XK001',
orderNo: 'ORD202205180001',
receiver: '张三',
phone: '13512341234',
status: '待发货',
creator: '管理员',
createTime: '2022-03-20 15:30:22'
}, {
id: 'XK002',
orderNo: 'ORD202205180002',
receiver: '张三',
phone: '13512341234',
status: '已实现',
creator: '管理员',
createTime: '2022-03-02 18:30:22'
}, {
id: 'XK003',
orderNo: 'ORD202205180003',
receiver: '张三',
phone: '13512341234',
status: '待收货',
creator: '管理员',
createTime: '2022-03-16 20:30:22'
}]
});
document.getElementById('table-tbody').innerHTML = html;
分页
因为表格是独自渲染了,就得再独自思考分页。
想要的成果:
我试了一下 boostrapPagination
,成果和想要的差异有点大,如下图所示,页数很多时没有思考...
的展现,且首尾页时默认暗藏头尾按钮。
最初,本人基于网上的一个简略的例子重写了一个分页的小插件,成果如下。
demo 页面:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>KPagination</title>
<!-- 引入 zepto CDN 链接 -->
<script src="https://cdnjs.gtimg.com/cdnjs/libs/zepto/1.1.4/zepto.js"></script>
<style>
body {font-size: 14px;}
button {
border-style: none;
line-height: 30px;
padding: 0 12px;
margin-bottom: 20px;
}
</style>
</head>
<body>
<button onclick="search()"> 搜寻 </button>
<div id="content"></div>
<div id="pagination"></div>
</body>
<script src="./js/kPagination.js"></script>
</html>
页面 JS:
function search() {
getKPagination({
total: 185,
totalPage: 18,
curPage: 1,
initCallback: function (page) {$('#content').html(` 以后页码:${page}`);
},
toPageCallback: function (page) {$('#content').html(` 以后页码:${page}`);
}
});
}
KPagination.js
function getKPagination(opt) {
const defaultOpt = {
totalPage: 0,
curPage: 1,
total: 0,
pageSize: 10,
bootstrapCss: false // 默认没引 bootstarp 款式。(此时会加上.pagination 相干的款式)}
const option = Object.assign({}, defaultOpt, opt);
const kPagination = {
curPage: option.curPage,
totalPage: option.totalPage,
total: option.total,
pageSize: option.pageSize,
toPageCallback: option.toPageCallback,
initCallback: option.initCallback,
pageEleID: 'pagination',
init: false,
getPaginationHtml: function (totalPage, curPage, total) {
var paginationInfo = "<ul class=\"pagination pagination-sm\">" +
"<li><span class=\"label\"> 共" + total + "条记录 </span></li>" +
"<li><a data-i=" + (curPage - 1) +
"data-disabled=\"" + ((curPage - 1) == 0 ? "true" : "false") + "\">«上一页 </a></li>";
if (totalPage <= 10) {for (var i = 1; i <= totalPage; i++) {
paginationInfo += "<li><a data-i=" + i +
">" + i + "</a></li>";
}
} else {if (curPage <= 3) {for (var i = 1; i <= curPage + 2; i++) {
paginationInfo += "<li><a data-i=" + i +
">" + i + "</a></li>";
}
paginationInfo += "<li><span class=\"label\">...</span></li>";
paginationInfo += "<li><a data-i=" + totalPage +
">" + totalPage + "</a></li>";
} else if (curPage <= totalPage - 5) {
paginationInfo += "<li><a data-i=" + 1 +
">" + 1 + "</a></li>";
paginationInfo += "<li><span class=\"label\">...</span></li>";
for (var i = curPage - 1; i <= curPage + 2; i++) {
paginationInfo += "<li><a data-i=" + i +
">" + i + "</a></li>";
}
paginationInfo += "<li><span class=\"label\">...</span></li>";
paginationInfo += "<li><a data-i=" + totalPage +
">" + totalPage + "</a></li>";
} else {
paginationInfo += "<li><a data-i=" + 1 +
">" + 1 + "</a></li>";
paginationInfo += "<li><span class=\"label\">...</span></li>";
for (var i = curPage - 1; i <= totalPage; i++) {
paginationInfo += "<li><a data-i=" + i +
">" + i + "</a></li>";
}
}
}
paginationInfo += "<li><a data-i=" + (curPage + 1) +
"data-disabled=\"" + (totalPage == 0 || curPage == totalPage ? "true" : "false") + "\"> 下一页»</a></li>";
return paginationInfo;
},
refreshPagination: function (totalPage, curPage, total) {if (total > 0 && (curPage < 1 || curPage > totalPage)) {return;}
var paginationInfo = this.getPaginationHtml(totalPage, curPage, total);
document.getElementById(this.pageEleID).innerHTML = paginationInfo;
$('.pagination li a').removeClass('current');
$('.pagination li a[data-i="' + curPage + '"]').addClass('current');
},
// 分页条初始化
init: function () {this.addStyle();
var paginationInfo = this.getPaginationHtml(this.totalPage, this.curPage, this.total);
document.getElementById(this.pageEleID).innerHTML = paginationInfo;
$('.pagination li a[data-i="' + this.curPage + '"]').addClass('current');
// 分页条点击切换查问
$('#' + this.pageEleID).on('click', '.pagination li a', (e) => {if (e.target.dataset['i'] == undefined) return false;
if (e.target.dataset['disabled'] == 'true') return false;
const page = parseInt(e.target.dataset['i']);
this.toPageCallback && this.toPageCallback(page);
this.refreshPagination(this.totalPage, page, this.total);
return false;
});
this.initCallback && this.initCallback(this.curPage);
},
addStyle: function () {
let style = '';
if (!this.bootstrapCss) {
style += `
.pagination {
display: inline-block;
padding-left: 0;
margin: 20px 0;
border-radius: 4px
}
.pagination>li {display: inline}
.pagination>li>a,.pagination>li>span {
position: relative;
float: left;
padding: 6px 12px;
margin-left: -1px;
line-height: 1.428571429;
text-decoration: none;
background-color: #fff;
border: 1px solid #ddd
}
.pagination>li:first-child>a,.pagination>li:first-child>span {
margin-left: 0;
border-bottom-left-radius: 4px;
border-top-left-radius: 4px
}
.pagination>li:last-child>a,.pagination>li:last-child>span {
border-top-right-radius: 4px;
border-bottom-right-radius: 4px
}
.pagination>li>a:hover,.pagination>li>span:hover,.pagination>li>a:focus,.pagination>li>span:focus {background-color: #eee}
.pagination>.active>a,.pagination>.active>span,.pagination>.active>a:hover,.pagination>.active>span:hover,.pagination>.active>a:focus,.pagination>.active>span:focus {
z-index: 2;
color: #fff;
cursor: default;
background-color: #488FCD;
border-color: #488FCD
}
.pagination>.disabled>span,.pagination>.disabled>a,.pagination>.disabled>a:hover,.pagination>.disabled>a:focus {
color: #999;
cursor: not-allowed;
background-color: #fff;
border-color: #ddd
}
.pagination-lg>li>a,.pagination-lg>li>span {
padding: 10px 16px;
font-size: 18px
}
.pagination-lg>li:first-child>a,.pagination-lg>li:first-child>span {
border-bottom-left-radius: 6px;
border-top-left-radius: 6px
}
.pagination-lg>li:last-child>a,.pagination-lg>li:last-child>span {
border-top-right-radius: 6px;
border-bottom-right-radius: 6px
}
.pagination-sm>li>a,.pagination-sm>li>span {
padding: 5px 10px;
font-size: 12px
}
.pagination-sm>li:first-child>a,.pagination-sm>li:first-child>span {
border-bottom-left-radius: 3px;
border-top-left-radius: 3px
}
.pagination-sm>li:last-child>a,.pagination-sm>li:last-child>span {
border-top-right-radius: 3px;
border-bottom-right-radius: 3px
}
`;
}
style += `
.pagination>li a:not([data-disabled="true"]):active{
color: #fff;
background: #488FCD;
border-color: #488FCD;
}
.pagination>li a:not([data-disabled="true"]).current {
color: #fff;
background: #488FCD;
border-color: #488FCD;
}
.pagination a[data-disabled="true"] {
color: #afafaf;
cursor: not-allowed;
}
.pagination a[data-disabled="true"]:hover {
color: #afafaf;
cursor: not-allowed;
}
.pagination>li>a{cursor:pointer;}
.pagination>li>a, .pagination>li>span {color: #333;}
.pagination>li .label,.pagination .label:hover{
cursor:initial;
background-color: #ffffff;
}
`;
const styleEle = document.createElement('style');
styleEle.type = 'text/css';
styleEle.innerText = style;
var head = document.getElementsByTagName('head')[0]
head.appendChild(styleEle);
}
}
kPagination.init();
return kPagination;
}
最初
良久没有这样比拟“原生态”的写前端了,哈哈哈,写写小工具小插件,还是感觉挺好玩的,这篇文章只是记录了:
- 页面渲染应用的是
art-template
模版引擎 - 简略封装了一个分页小插件的
KPagination.js
本次开发工作的笔记待续哦,前面还会补充其余性能的一些总结。
欢送大家戳戳留下足迹,欢送留言交换哦~
参考文献
- Bootstrap 前端分页的实现(带省略号)