前言

近几年基本都是开发SPA应用,朋友找我帮忙做一个简单的后台管理的模块,是传统的ASP.NET WEB页面,不过我这次还是写独立的前端界面的,只是会基于他们系统使用的框架去开发(jq+bootstrap)。

任务

  • 列表页(搜索、表格展示、分页)
  • 表单提交页(新增/编辑)

技术框架

例子:https://blog.csdn.net/weixin_...

开发笔记

原项目用的是v3版本的bootstrap

表格

原项目中表格有用bootstrapTable插件(功能看着挺齐全),由于其官网例子很多加载不出来(控制台报错),自己对它不熟悉,且任务时间紧担心用了后面要扩展不方便,我就没用它的。

表格我是请求数据后,直接用art-template模版引擎去渲染,简单的示例界面如下:
image.png
界面:

<!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;

分页

由于表格是单独渲染了,就得再单独考虑分页。
想要的效果:
image.png
我试了一下boostrapPagination,效果和想要的差别有点大,如下图所示,页数很多时没有考虑...的展示,且首尾页时默认隐藏头尾按钮。
image.png
最后,自己基于网上的一个简单的例子重写了一个分页的小插件,效果如下。
图像.gif
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
本次开发任务的笔记待续哦,后面还会补充其他功能的一些总结。
欢迎大家戳戳留下脚印,欢迎留言交流哦~

参考文献


慢条斯理的小可
2 声望1 粉丝