贺新年,发布node.js适用的后台分页代码类(高仿ThinkPHP)
发布于 8 年前 作者 zengming00 4052 次浏览 最后一次编辑是 6 年前 来自 分享

废话不多说,先上效果图,注意,GET参数可以完全保留!

QQ截图20170118211641.jpg

注意ejs模板输出时应该使用 <%-page %> 是‘%-’不是’%='因为等号会转义html标签

<%-page %>

测试模板

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<style>
    .page .num,.page .current{margin: 2px;}
    .page .current{color: red;font-weight: bold;}
</style>
<%=limit %>
<hr/>
<%-page %>
</body>
</html>

测试代码

router.get('/', function(req, res, next) {
    var $page = new Page(req, 51, 10);
    var data = {
        limit: "limit {" + $page.firstRow + "," + $page.listRows + "}",
	    page: $page.show()
    };
    res.render('Page/index',data);
});

完整的类实现(其实就是照抄ThinkPHP,具体的用法和功能基本上和ThinkPHP框架的说明是完全一样的)

///////////////Copyright zengming QQ:243786753 2010-2017/////////////////////////////////////////////
///////////////    [MIT](LICENSE)   2017/01/18 21:19    /////////////////////////////////////////////
function str_replace(search, replace, str) {
    var old,rep;
    for(var i=0; i<search.length; i++){
        rep = replace[i] ? replace[i] : '';
        do{
            old = str;
            str = str.replace(search[i],rep);
        }while(str != old); //替换后的字符串与原字符串不同,表示发生了替换,但replace有可能只替换了一次
    }
    return str;
}
function isEmptyObject(e) {
    for (var t in e)  return false;
    return true;
}

exports = module.exports = function Page(req, totalRows, listRows){
    var pageTag = "PAGE"; //url参数替换标记
    var p       = 'p'; //分页参数名
    var url     = req.originalUrl; //当前链接URL
    // 分页显示定制
    var config  = {
        'header': '<span class="rows">共 %TOTAL_ROW% 条记录</span>',
        'prev': '<<',
        'next': '>>',
        'first': '1...',
        'last': '...%TOTAL_PAGE%',
        'theme': '%FIRST% %UP_PAGE% %LINK_PAGE% %DOWN_PAGE% %END%'
    };

    /* 基础设置 */
    this.rollPage   = 11;// 分页栏每页显示的页数
    this.lastSuffix = true; // 最后一页是否显示总页数
    this.totalRows  = totalRows; //设置总记录数
    this.listRows   = listRows || 20;  //设置每页显示行数
    this.nowPage    = req.query[p] ? (req.query[p]|0) : 1;
    this.nowPage    = this.nowPage>0 ? this.nowPage : 1;
    this.firstRow   = this.listRows * (this.nowPage - 1);// 起始行数  (可能由于get参数的影响导致起始行超过总行数,但不影响使用)

    if(url.indexOf('?') != -1){ //  "/page/haha?p=1234&a=1"
        url = url.substring(0,url.indexOf('?'))
    }
    url += '?';
    if(isEmptyObject(req.query)){
        url +=  p+"="+pageTag;
    }else{
        req.query[p]=pageTag;
        for(var i in req.query){
            url += i + "=" + encodeURIComponent(req.query[i]) + "&";
        }
    }

    /**
     * 定制分页链接设置
     * @param string $name  设置名称
     * @param string $value 设置值
     */
    this.setConfig = function setConfig($name,$value) {
        if(config[$name]) { config[$name] = $value; }
    }

    /**
     * 生成链接URL
     * @param  integer $page 页码
     * @return string
     */
    var makeUrl = function makeUrl($page){
        return url.replace(pageTag, $page);
    }

    /**
     * 组装分页链接
     * @return string
     */
    this.show = function show() {
        if(0 == this.totalRows) return '';

        /* 计算分页信息 */
        this.totalPages = Math.ceil(this.totalRows / this.listRows); //总页数
        if(this.totalPages && this.nowPage > this.totalPages) {
            this.nowPage = this.totalPages;
        }

        /* 计算分页临时变量 */
        var $now_cool_page      = this.rollPage/2;
        var $now_cool_page_ceil = Math.ceil($now_cool_page);
        if(this.lastSuffix){
            config['last'] = this.totalPages;
        }

        //上一页
        var $up_row  = this.nowPage - 1;
        var $up_page = $up_row > 0 ? '<a class="prev" href="' + makeUrl($up_row) + '">' + config['prev'] + '</a>' : '';

        //下一页
        var $down_row  = this.nowPage + 1;
        var $down_page = ($down_row <= this.totalPages) ? '<a class="next" href="' + makeUrl($down_row) + '">' + config['next'] + '</a>' : '';

        //第一页
        var $the_first = '';
        if(this.totalPages > this.rollPage && (this.nowPage - $now_cool_page) >= 1){
            $the_first = '<a class="first" href="' + makeUrl(1) + '">' + config['first'] + '</a>';
        }

        //最后一页
        var $the_end = '';
        if(this.totalPages > this.rollPage && (this.nowPage + $now_cool_page) < this.totalPages){
            $the_end = '<a class="end" href="' + makeUrl(this.totalPages) + '">' + config['last'] + '</a>';
        }

        //数字连接
        var $link_page = "";
        var $page = 0;
        for(var $i = 1; $i <= this.rollPage; $i++){
            if((this.nowPage - $now_cool_page) <= 0 ){
                $page = $i;
            }else if((this.nowPage + $now_cool_page - 1) >= this.totalPages){
                $page = this.totalPages - this.rollPage + $i;
            }else{
                $page = this.nowPage - $now_cool_page_ceil + $i;
            }
            if($page > 0 && $page != this.nowPage){
                if($page <= this.totalPages){
                    $link_page += '<a class="num" href="' + makeUrl($page) + '">' + $page + '</a>';
                }else{
                    break;
                }
            }else{
                if($page > 0 && this.totalPages != 1){
                    $link_page += '<span class="current">' + $page + '</span>';
                }
            }
        }

        //替换分页内容
        var $page_str = str_replace(
            ['%HEADER%', '%NOW_PAGE%', '%UP_PAGE%', '%DOWN_PAGE%', '%FIRST%', '%LINK_PAGE%', '%END%', '%TOTAL_ROW%', '%TOTAL_PAGE%'],
            [config['header'], this.nowPage, $up_page, $down_page, $the_first, $link_page, $the_end, this.totalRows, this.totalPages],
            config['theme']);
        return "<div class='page'>" + $page_str + "</div>";
    }
}

潜在风险

由于当时是直接移植TP的分页类,发现存在XSS风险,此份代码没有进行修正: index.html?a=b //对b进行了过滤,但没对a进行过滤 index.html?"><script>alert(1)</script>=1 //这将会直接输出到页面中(现在浏览器可以自动检测和拦截,但不排除其它方式绕过) 解决办法:对get参数的参数名进行过滤

license

MIT

4 回复

北京考虑么?

@i5ting 去北京那不是舍近求远吗

@zengming00 看错了,是广东不是广州,哈哈,深圳也不少node呢

这个水平拿个7k完全可以的,代码风格也不错,加点es6装b更好…

回到顶部