NiceGui 3.4.0 的 ui.pagination 分页实现 例子

标准的分页实现

python 复制代码
from nicegui import ui

class StandardPagination:
    def __init__(self):
        # 模拟数据
        self.all_items = [f'卡片 {i+1}' for i in range(50)]
        
        # 分页参数
        self.current_page = 1
        self.items_per_page = 5
        self.total_items = len(self.all_items)
        self.total_pages = (self.total_items + self.items_per_page - 1) // self.items_per_page
        
        # 创建界面
        self.create_ui()
    
    def create_ui(self):
        # 标题
        ui.label('卡片分页显示').classes('text-2xl font-bold mb-4')
        
        # 分页控件
        with ui.row().classes('w-full justify-center'):
            # 使用正确的参数顺序
            self.pagination = ui.pagination(
                1,  # min
                self.total_pages,  # max
                direction_links=True,  # 显示上一页/下一页
                value=self.current_page,  # 当前页码
                on_change=self.on_page_change
            )
        
        # 显示当前页码
        ui.label().bind_text_from(
            self.pagination, 'value', 
            lambda v: f'第 {v} 页 / 共 {self.total_pages} 页'
        ).classes('text-center mt-2')
        
        # 卡片容器
        self.cards_container = ui.column().classes('w-full gap-3 mt-4')
        
        # 加载初始数据
        self.load_cards()
    
    def on_page_change(self, e):
        self.current_page = e.value
        self.load_cards()
    
    def load_cards(self):
        """加载当前页的卡片"""
        # 清除旧卡片
        self.cards_container.clear()
        
        # 计算当前页的数据范围
        start_idx = (self.current_page - 1) * self.items_per_page
        end_idx = min(start_idx + self.items_per_page, self.total_items)
        
        # 创建新卡片
        for i in range(start_idx, end_idx):
            with self.cards_container:
                with ui.card().tight().classes('w-full hover:shadow-md transition-shadow'):
                    with ui.card_section():
                        ui.label(f'{self.all_items[i]}').classes('text-lg font-bold')
                        ui.label(f'这是第 {i+1} 张卡片的内容描述...')
                    with ui.card_actions():
                        ui.button('查看', icon='visibility').props('size=sm')
                        ui.button('编辑', icon='edit').props('size=sm flat')

# 运行应用
StandardPagination()
ui.run()

增强版:带搜索和每页数量选择

python 复制代码
from nicegui import ui

class EnhancedPagination:
    def __init__(self):
        self.all_items = [f'卡片数据 {i+1}' for i in range(100)]
        self.filtered_items = self.all_items.copy()
        
        self.current_page = 1
        self.items_per_page = 8
        self.total_pages = 1
        
        self.create_ui()
        self.update_pagination()
    
    def create_ui(self):
        # 标题
        ui.label('卡片管理系统').classes('text-2xl font-bold mb-6')
        
        # 搜索和设置区域
        with ui.row().classes('w-full items-center mb-6'):
            # 搜索框
            self.search_input = ui.input(
                placeholder='输入关键词搜索...',
                on_change=self.on_search
            ).props('outlined dense').classes('w-64')
            
            # 每页数量选择
            self.page_size_select = ui.select(
                [4, 8, 12, 20],
                value=self.items_per_page,
                on_change=self.on_page_size_change,
                label='每页显示'
            ).props('outlined dense').classes('w-32')
            
            # 统计信息
            self.stats_label = ui.label('').classes('ml-auto')
        
        # 分页控件
        with ui.row().classes('w-full justify-center mb-4'):
            self.pagination = ui.pagination(
                1,  # min
                1,  # max (初始值,后面更新)
                direction_links=True,
                value=1,
                on_change=self.on_page_change
            )
        
        # 卡片容器
        self.cards_container = ui.column().classes('w-full gap-4')
        
        # 底部信息
        self.page_info = ui.label('').classes('text-center mt-4 text-gray-600')
    
    def update_pagination(self):
        """更新分页控件和数据"""
        # 计算总页数
        self.total_pages = max(1, (len(self.filtered_items) + self.items_per_page - 1) // self.items_per_page)
        
        # 更新分页控件的最大页码
        self.pagination._props['max'] = self.total_pages
        
        # 确保当前页码在有效范围内
        if self.current_page > self.total_pages:
            self.current_page = self.total_pages
        
        # 更新分页控件的当前值
        self.pagination.value = self.current_page
        
        # 更新统计信息
        total = len(self.filtered_items)
        start = (self.current_page - 1) * self.items_per_page + 1
        end = min(self.current_page * self.items_per_page, total)
        
        self.stats_label.text = f'共 {total} 条记录'
        self.page_info.text = f'显示第 {start}-{end} 条,共 {total} 条'
        
        # 重新加载卡片
        self.load_cards()
    
    def on_search(self, e):
        """搜索处理"""
        keyword = e.value.lower()
        if keyword:
            self.filtered_items = [
                item for item in self.all_items 
                if keyword in item.lower()
            ]
        else:
            self.filtered_items = self.all_items.copy()
        
        self.current_page = 1
        self.update_pagination()
    
    def on_page_size_change(self, e):
        """每页数量改变"""
        self.items_per_page = e.value
        self.current_page = 1
        self.update_pagination()
    
    def on_page_change(self, e):
        """页码改变"""
        self.current_page = e.value
        self.update_pagination()
    
    def load_cards(self):
        """加载卡片"""
        self.cards_container.clear()
        
        if not self.filtered_items:
            with self.cards_container:
                ui.label('没有找到相关数据').classes(
                    'text-center text-gray-500 py-8 text-lg'
                )
            return
        
        # 计算当前页数据
        start_idx = (self.current_page - 1) * self.items_per_page
        end_idx = min(start_idx + self.items_per_page, len(self.filtered_items))
        
        # 创建卡片网格
        for i in range(start_idx, end_idx):
            with self.cards_container:
                with ui.card().classes('w-full'):
                    # 卡片头部
                    with ui.row().classes('items-center justify-between p-4'):
                        ui.label(f'{self.filtered_items[i]}').classes(
                            'text-xl font-bold text-blue-700'
                        )
                        ui.badge(f'ID: {i+1:03d}', color='primary')
                    
                    # 卡片内容
                    with ui.column().classes('p-4 pt-0'):
                        ui.label('这是一个示例卡片,包含一些描述性内容。').classes(
                            'text-gray-600'
                        )
                        
                        with ui.row().classes('mt-3 gap-2'):
                            ui.badge('标签1', color='green')
                            ui.badge('标签2', color='orange')
                            ui.badge('标签3', color='purple')
                    
                    # 卡片操作
                    with ui.row().classes('justify-end p-4 pt-0 gap-2'):
                        ui.button('查看详情', icon='info').props('size=sm outline')
                        ui.button('编辑', icon='edit').props('size=sm flat')
                        ui.button('删除', icon='delete').props('size=sm flat color=negative')

# 运行应用
EnhancedPagination()
ui.run(title='卡片分页管理系统')

响应式网格布局版本

python 复制代码
from nicegui import ui

class GridPagination:
    def __init__(self):
        # 生成测试数据
        self.items = []
        for i in range(1, 51):
            self.items.append({
                'id': i,
                'title': f'产品卡片 {i}',
                'description': f'这是第 {i} 个产品的详细描述信息',
                'price': f'¥{99 + i * 10}',
                'tags': ['热销', '新品', '推荐'][:i % 3 + 1]
            })
        
        self.current_page = 1
        self.items_per_page = 9  # 3x3 网格
        self.total_pages = (len(self.items) + self.items_per_page - 1) // self.items_per_page
        
        self.create_ui()
    
    def create_ui(self):
        # 响应式布局容器
        with ui.column().classes('w-full max-w-6xl mx-auto p-4'):
            # 标题
            ui.label('产品卡片展示').classes(
                'text-3xl font-bold text-center mb-8 text-gray-800'
            )
            
            # 分页控件(顶部)
            with ui.row().classes('w-full justify-between items-center mb-6'):
                ui.label('产品列表').classes('text-xl font-semibold')
                
                self.pagination = ui.pagination(
                    1,
                    self.total_pages,
                    direction_links=True,
                    value=self.current_page,
                    on_change=self.on_page_change
                )
            
            # 卡片网格容器
            self.grid_container = ui.row().classes(
                'flex-wrap justify-center gap-4 w-full'
            )
            
            # 分页控件(底部)
            with ui.row().classes('w-full justify-center mt-8'):
                self.bottom_pagination = ui.pagination(
                    1,
                    self.total_pages,
                    direction_links=True,
                    value=self.current_page,
                    on_change=self.on_page_change
                )
            
            # 页面信息
            with ui.row().classes('w-full justify-center mt-4'):
                ui.label().bind_text_from(
                    self.pagination, 'value',
                    lambda v: f'第 {v} 页 / 共 {self.total_pages} 页'
                ).classes('text-gray-600')
            
            # 初始加载
            self.load_grid()
    
    def on_page_change(self, e):
        """页码改变事件"""
        self.current_page = e.value
        self.load_grid()
        # 同步两个分页组件的值
        self.bottom_pagination.value = self.current_page
    
    def load_grid(self):
        """加载网格卡片"""
        self.grid_container.clear()
        
        # 计算当前页数据范围
        start_idx = (self.current_page - 1) * self.items_per_page
        end_idx = min(start_idx + self.items_per_page, len(self.items))
        
        # 创建卡片网格
        for i in range(start_idx, end_idx):
            item = self.items[i]
            with self.grid_container:
                with ui.card().classes(
                    'w-80 hover:shadow-xl transition-all duration-300 '
                    'hover:-translate-y-1 border border-gray-200'
                ):
                    # 卡片顶部图片区域
                    with ui.card_section().classes('p-0'):
                        ui.image(f'https://picsum.photos/seed/{item["id"]}/320/180').classes(
                            'w-full h-48 object-cover'
                        )
                    
                    # 卡片内容
                    with ui.card_section().classes('p-4'):
                        # 标题和价格
                        with ui.row().classes('justify-between items-start'):
                            ui.label(item['title']).classes(
                                'text-lg font-bold text-gray-800'
                            )
                            ui.label(item['price']).classes(
                                'text-xl font-bold text-red-600'
                            )
                        
                        # 描述
                        ui.label(item['description']).classes(
                            'text-gray-600 mt-2 text-sm'
                        )
                        
                        # 标签
                        with ui.row().classes('flex-wrap gap-1 mt-3'):
                            for tag in item['tags']:
                                ui.badge(tag, color=self.get_tag_color(tag))
                    
                    # 卡片操作按钮
                    with ui.card_actions().classes('px-4 pb-4'):
                        ui.button('加入购物车', icon='shopping_cart', 
                                 color='primary').props('size=sm')
                        ui.button('收藏', icon='favorite_border').props(
                            'size=sm flat'
                        )
                        ui.button('详情', icon='chevron_right').props(
                            'size=sm flat'
                        )
    
    def get_tag_color(self, tag):
        """根据标签返回颜色"""
        colors = {
            '热销': 'red',
            '新品': 'green',
            '推荐': 'blue',
            '特价': 'orange',
            '限时': 'purple'
        }
        return colors.get(tag, 'gray')

# 运行应用
GridPagination()
ui.run()

关键点说明:

  1. 正确的 ui.pagination 参数顺序

    python 复制代码
    ui.pagination(min, max, direction_links=True, value=current_page, on_change=callback)
  2. 双向绑定

    python 复制代码
    # 绑定分页值到标签
    ui.label().bind_text_from(pagination, 'value', lambda v: f'Page {v}')
  3. 响应式设计

    • 使用 Tailwind CSS 类实现响应式
    • 在移动端和桌面端都能良好显示

实现方式更加简洁,符合 NiceGUI 的设计。

相关推荐
涡能增压发动积17 小时前
同样的代码循环 10次正常 循环 100次就抛异常?自定义 Comparator 的 bug 让我丢尽颜面
后端
Wenweno0o17 小时前
0基础Go语言Eino框架智能体实战-chatModel
开发语言·后端·golang
于慨17 小时前
Lambda 表达式、方法引用(Method Reference)语法
java·前端·servlet
石小石Orz17 小时前
油猴脚本实现生产环境加载本地qiankun子应用
前端·架构
swg32132117 小时前
Spring Boot 3.X Oauth2 认证服务与资源服务
java·spring boot·后端
从前慢丶17 小时前
前端交互规范(Web 端)
前端
tyung17 小时前
一个 main.go 搞定协作白板:你画一笔,全世界都看见
后端·go
gelald17 小时前
SpringBoot - 自动配置原理
java·spring boot·后端
CHU72903517 小时前
便捷约玩,沉浸推理:线上剧本杀APP功能版块设计详解
前端·小程序
GISer_Jing17 小时前
Page-agent MCP结构
前端·人工智能