QML 实现一个简易的分页组件

当列表数据项较多的时候,会有分页展示的需求,可能需要展示数据总数、每页显示数、总页数、当前页数等。

因为数据可能是通过网络分页请求得到,或者本地数据会刷新,那么这些信息就得通过外部设置,组件只负责请求和展示页码信息就行了。点击某一页之后先预设置为该页按钮高亮,待数据返回后根据参数重新设置。

主要难点就在页码按钮数值的计算、显示隐藏上了,剩下的样式就根据需求调整。

效果展示:

主要实现代码:

(github链接:https://github.com/gongjianbo/MyTestCode/tree/master/Qml/QmlPagination )

(分页组件、分页按钮、main三个文件)

import QtQuick 2.12
import QtQuick.Controls 2.12

//自定义分页组件 Pagination
//龚建波 2020-12-19
//1.负责页码展示和发送翻页请求,实际页码计算由后端or业务逻辑进行
//每次请求返回后根据计算好的页码设置值,pageCurrent、itemCount
//2.可以在返回之前ui先根据之前的参数计算用于展示,但要注意绑定关系
//实现中我对pageCurrent直接赋值,要绑定需要加Connections
Rectangle {
    id: control

    //请求某一页
    //page: 页码
    //count: 一页总数
    signal requestPage(int page,int count)

    //需求中要展示的信息:数据总条数,每页条数,当前页,页跳转
    //当前页
    property int pageCurrent: 0
    //数据总数
    property int itemCount: 0
    //总页数
    property int pageCount: itemCount>0?Math.ceil(itemCount/__itemPerPage):0
    //每页条数,这个和box关联的,暂时默认初始化
    property int __itemPerPage: 20
    //页码按钮显示个数
    property int pageButtonCount: 5
    property int __pageButtonHalf: Math.floor(pageButtonCount/2)+1
    property font font
    font{
        pixelSize: 14
        family: "Microsoft YaHei"
    }
    property color textColor: "#666666"
    property color highlightedColor: "#1989FA"
    property color elementBorderColor: "#DCDFE6"
    property int elementHeight: 30
    property alias padding: content_row.padding

    //color: "transparent"
    //border.color: "gray"
    //radius: 4
    implicitHeight: 40
    implicitWidth: content_row.width

    Row{
        id: content_row
        height: control.height
        spacing: 25
        padding: 10

        //总条数
        Text{
            anchors.verticalCenter: parent.verticalCenter
            font: control.font
            color: control.textColor
            text: "共 "+control.itemCount+" 条"
        }

        //每页多少条
        Row{
            spacing: 5
            anchors.verticalCenter: parent.verticalCenter
            Text{
                anchors.verticalCenter: parent.verticalCenter
                font: control.font
                color: control.textColor
                text: "每页"
            }
            ComboBox{
                id: item_page_box
                width: 90
                height: control.elementHeight
                model: [10,20,50,100]
                currentIndex: 1
                font: control.font
                onCurrentIndexChanged: {
                    //选择每页数后重新请求数据
                    //currentText此时还未修改
                    //设置页码后从1开始
                    control.__itemPerPage=model[currentIndex];
                    control.pageCurrent=1;
                    control.requestPage(control.pageCurrent,control.__itemPerPage);
                }
            }
            Text{
                anchors.verticalCenter: parent.verticalCenter
                font: control.font
                color: control.textColor
                text: "条"
            }
        }
        //页码按钮
        Row{
            spacing: 5
            anchors.verticalCenter: parent.verticalCenter
            //左侧前一页,应该使用图片,这里仅作演示
            PageButton{
                visible: control.pageCount>1
                enabled: control.pageCurrent>1
                anchors.verticalCenter: parent.verticalCenter
                width: 30
                height: 30
                font: control.font
                textColor: control.textColor
                highlightedColor: control.highlightedColor
                text: "<"
                onClicked: {
                    control.calcNewPage(control.pageCurrent-1);
                }
            }
            //中间显示页码
            Row{
                spacing: 5
                anchors.verticalCenter: parent.verticalCenter
                //第一页
                PageButton{
                    visible: control.pageCount>0
                    width: 30
                    height: control.elementHeight
                    font: control.font
                    textColor: control.textColor
                    highlightedColor: control.highlightedColor
                    pageNumber: 1
                    pageCurrent: control.pageCurrent
                    onClicked: {
                        control.calcNewPage(1);
                    }
                }
                Text {
                    //pageCount<btnCount不用显示
                    //当前页在前countHalf页不用显示
                    visible: (control.pageCount>control.pageButtonCount&&
                              control.pageCurrent>control.__pageButtonHalf)
                    text: "..."
                    font: control.font
                    color: control.textColor
                    height: control.elementHeight
                }
                //中间的页码由Repeater根据设置的pageButtonCount创建
                Repeater{
                    id: button_repeator
                    model: (control.pageCount<2)
                           ?0
                           :(control.pageCount>=control.pageButtonCount)
                             ?(control.pageButtonCount-2)
                             :(control.pageCount-2)
                    delegate: PageButton{
                        width: 30
                        height: control.elementHeight
                        font: control.font
                        textColor: control.textColor
                        highlightedColor: control.highlightedColor
                        //在首或者尾相连时,值要连续,避免和首尾重复
                        pageNumber: (control.pageCurrent<=control.__pageButtonHalf)
                                    ?(2+index)
                                    :(control.pageCount-control.pageCurrent<=control.pageButtonCount-control.__pageButtonHalf)
                                      ?(control.pageCount-button_repeator.count+index)
                                      :(control.pageCurrent+2+index-control.__pageButtonHalf)
                        pageCurrent: control.pageCurrent
                        onClicked: {
                            control.calcNewPage(pageNumber);
                        }
                    }
                }
                Text {
                    id: page_moreright
                    //pageCount<btnCount不用显示
                    //当前页在倒数countHalf页不用显示
                    visible: (control.pageCount>control.pageButtonCount&&
                              control.pageCount-control.pageCurrent>control.pageButtonCount-control.__pageButtonHalf)
                    text: "..."
                    font: control.font
                    color: control.textColor
                    height: control.elementHeight
                }
                //最后一页
                PageButton{
                    visible: control.pageCount>1
                    width: 30
                    height: control.elementHeight
                    font: control.font
                    textColor: control.textColor
                    highlightedColor: control.highlightedColor
                    pageNumber: control.pageCount
                    pageCurrent: control.pageCurrent
                    onClicked: {
                        control.calcNewPage(pageNumber);
                    }
                }
            }
            //右侧下一页,应该使用图片,这里仅作演示
            PageButton{
                visible: control.pageCount>1
                enabled: control.pageCurrent<control.pageCount
                anchors.verticalCenter: parent.verticalCenter
                width: 30
                height: 30
                font: control.font
                textColor: control.textColor
                highlightedColor: control.highlightedColor
                text: ">"
                onClicked: {
                    control.calcNewPage(control.pageCurrent+1);
                }
            }
        }
        //页码跳转
        Row{
            spacing: 5
            anchors.verticalCenter: parent.verticalCenter
            Text{
                anchors.verticalCenter: parent.verticalCenter
                font: control.font
                color: control.textColor
                text: "前往"
            }
            TextField{
                id: edit_goto_page
                width: 60
                height: control.elementHeight
                text: "1"
                font: control.font
                color: control.textColor
                validator: IntValidator{
                    bottom: 0
                    top: 999999
                }
                selectByMouse: true
                selectedTextColor: "white"
                selectionColor: "blue"
                background: Rectangle{
                    border.color: control.elementBorderColor
                }

                Keys.onPressed: {
                    //enter小键盘enter
                    //return主键盘enter
                    if(event.key===Qt.Key_Enter||event.key===Qt.Key_Return){
                        focus=false;
                        if(edit_goto_page.text){
                            //编辑结束就去请求该页数据
                            control.requestPage(Number(edit_goto_page.text),control.__itemPerPage);
                        }
                    }
                }
            }
            Text{
                anchors.verticalCenter: parent.verticalCenter
                font: control.font
                color: control.textColor
                text: "页"
            }
        }
    }

    //翻页计算
    function calcNewPage(page)
    {
        if(!page)
            return;
        let page_num=Number(page);
        //超出范围或者为当前页就返回
        if(page_num<1||page_num>control.pageCount||page_num===control.pageCurrent)
            return;
        control.pageCurrent=page_num;
        control.requestPage(page_num,control.__itemPerPage)
    }
}
import QtQuick 2.12
import QtQuick.Controls 2.12

//分页组件上的页码按钮 PageButton
//龚建波 2020-12-20
Button {
    id: control

    //该按钮代表的页码
    property int pageNumber: -2
    //当前选中的页码
    property int pageCurrent: -3
    property color textColor: "#666666"
    property color highlightedColor: "#1989FA"

    implicitWidth: implicitContentWidth+leftPadding+rightPadding
    implicitHeight: implicitContentHeight+topPadding+bottomPadding
    padding: 0
    text: pageNumber

    contentItem: Text {
        text: control.text
        font: control.font
        color: pageNumber===pageCurrent?highlightedColor:textColor
        opacity: enabled ? 1.0 : 0.3
        horizontalAlignment: Text.AlignHCenter
        verticalAlignment: Text.AlignVCenter
    }

    //暂时没有背景,可以加一个小圆圈背景
    background: Item {
    }
}
import QtQuick 2.12
import QtQuick.Window 2.12

Window {
    width: 640
    height: 480
    visible: true
    title: qsTr("龚建波 1992")

    Pagination{
        x: 10
        y: 10
        height: 40
        //width: parent.width-20
        border.color: "gray"
        radius: 4

        pageCurrent: 1
        itemCount: 99
        //触发信号后去请求该页数据,并更新当前页码和总数等
        onRequestPage: {
            console.log("Pagination1 request page:",page,"count:",count)
            pageCurrent=page;
        }
    }

    Pagination{
        x: 10
        y: 60
        height: 40
        //width: parent.width-20
        border.color: "gray"
        radius: 4

        pageCurrent: 1
        itemCount: 31
        //触发信号后去请求该页数据,并更新当前页码和总数等
        onRequestPage: {
            console.log("Pagination1 request page:",page,"count:",count)
            pageCurrent=page;
        }
    }
}

 

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

龚建波

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值