unibest分页组件:z-paging高级用法

【免费下载链接】unibest unibest - 最好用的 uniapp 开发框架。unibest 是由 uniapp + Vue3 + Ts + Vite5 + UnoCss + WotUI 驱动的跨端快速启动模板,使用 VS Code 开发,具有代码提示、自动格式化、统一配置、代码片段等功能,同时内置了大量平时开发常用的基本组件,开箱即用,让你编写 uniapp 拥有 best 体验。 【免费下载链接】unibest 项目地址: https://gitcode.com/feige996/unibest

还在为uniapp列表分页开发而烦恼?数据加载、下拉刷新、上拉加载、空状态处理等问题是否让你头疼不已?本文将深入解析unibest框架中z-paging组件的高级用法,让你彻底掌握企业级分页开发技巧。

通过本文你将学会:

  • z-paging核心配置与最佳实践
  • 多种数据源对接方案(RESTful API、GraphQL、本地数据)
  • 高级功能:自定义加载动画、复杂空状态处理、多Tab切换
  • 性能优化与常见问题解决方案

一、z-paging核心架构解析

z-paging作为uniapp生态中最强大的分页组件,其架构设计遵循MVVM模式,提供了完整的生命周期管理。

mermaid

1.1 基础配置示例

<template>
  <z-paging
    ref="pagingRef"
    v-model:data="dataList"
    :fixed="false"
    :auto-show-back-to-top="true"
    :auto-scroll-to-top-when-reload="true"
    @query="queryList"
  >
    <template #default="{ item }">
      <view class="item">
        <text>{{ item.title }}</text>
        <text>{{ item.createTime }}</text>
      </view>
    </template>
    
    <template #loading>
      <u-loading mode="circle" />
    </template>
    
    <template #empty>
      <u-empty mode="data" />
    </template>
  </z-paging>
</template>

<script lang="ts" setup>
import { ref } from 'vue'
import type { ZPaging } from 'z-paging'

const pagingRef = ref<ZPaging>()
const dataList = ref<any[]>([])

// 分页查询方法
const queryList = async (pageNo: number, pageSize: number) => {
  try {
    const params = { pageNo, pageSize }
    const response = await api.getList(params)
    
    // 必须返回数组和总条数
    return {
      data: response.data.list,
      total: response.data.total
    }
  } catch (error) {
    // 错误处理
    pagingRef.value?.complete(false)
    throw error
  }
}
</script>

二、多数据源接入方案

2.1 RESTful API对接

// 使用alova进行请求封装
import { createAlova } from 'alova'
import { uniRequestAdapter } from '@alova/adapter-uniapp'

const alovaInstance = createAlova({
  baseURL: 'https://api.example.com',
  requestAdapter: uniRequestAdapter(),
  responded: response => response.json()
})

// 分页请求Hook
export const usePagingRequest = (url: string) => {
  const request = (pageNo: number, pageSize: number) => {
    return alovaInstance.Get(url, {
      params: { pageNo, pageSize }
    })
  }
  
  return { request }
}

2.2 GraphQL分页方案

// GraphQL分页查询
const queryListGraphQL = async (pageNo: number, pageSize: number) => {
  const query = `
    query GetList($page: Int!, $size: Int!) {
      items(page: $page, size: $size) {
        list {
          id
          title
          content
          createTime
        }
        total
      }
    }
  `
  
  const variables = { page: pageNo, size: pageSize }
  const response = await graphqlClient.request(query, variables)
  
  return {
    data: response.items.list,
    total: response.items.total
  }
}

2.3 本地数据分页

// 本地大数据集分页
const localDataPaging = (pageNo: number, pageSize: number, allData: any[]) => {
  const start = (pageNo - 1) * pageSize
  const end = start + pageSize
  const pageData = allData.slice(start, end)
  
  return {
    data: pageData,
    total: allData.length
  }
}

三、高级功能实战

3.1 自定义加载动画与状态

<template>
  <z-paging
    ref="pagingRef"
    v-model:data="dataList"
    :loading-more-enabled="true"
    :hide-empty-view="true"
    @query="queryList"
  >
    <!-- 自定义加载状态 -->
    <template #loading>
      <view class="custom-loading">
        <u-loading-icon size="36" color="#2979ff" />
        <text class="loading-text">拼命加载中...</text>
      </view>
    </template>
    
    <!-- 自定义加载更多 -->
    <template #loadingMoreDefault>
      <view class="load-more-default">
        <text>上拉加载更多</text>
      </view>
    </template>
    
    <template #loadingMoreLoading>
      <view class="load-more-loading">
        <u-loading-icon size="24" />
        <text>加载中...</text>
      </view>
    </template>
    
    <template #loadingMoreNoMore>
      <view class="load-more-nomore">
        <text>没有更多数据了</text>
      </view>
    </template>
  </z-paging>
</template>

<style scoped>
.custom-loading {
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 40rpx 0;
}

.loading-text {
  margin-top: 20rpx;
  color: #999;
  font-size: 28rpx;
}

.load-more-default,
.load-more-loading,
.load-more-nomore {
  padding: 30rpx 0;
  text-align: center;
  color: #999;
  font-size: 28rpx;
}
</style>

3.2 复杂空状态处理

<template>
  <z-paging
    ref="pagingRef"
    v-model:data="dataList"
    :hide-empty-view="true"
    @query="queryList"
  >
    <template #empty>
      <view class="empty-container">
        <!-- 网络错误空状态 -->
        <template v-if="networkError">
          <u-empty mode="network" />
          <button class="retry-btn" @click="retry">重试</button>
        </template>
        
        <!-- 搜索无结果 -->
        <template v-else-if="isSearching">
          <u-empty mode="search" />
          <text class="empty-text">换个关键词试试吧</text>
        </template>
        
        <!-- 默认空状态 -->
        <template v-else>
          <u-empty mode="data" />
          <text class="empty-text">暂无数据</text>
        </template>
      </view>
    </template>
  </z-paging>
</template>

<script lang="ts" setup>
import { ref } from 'vue'

const networkError = ref(false)
const isSearching = ref(false)

const retry = () => {
  networkError.value = false
  pagingRef.value?.reload()
}
</script>

3.3 多Tab切换分页

<template>
  <view class="container">
    <!-- Tab切换 -->
    <u-tabs
      :list="tabList"
      :current="currentTab"
      @change="tabChange"
    />
    
    <!-- 分页组件 -->
    <z-paging
      ref="pagingRef"
      v-model:data="dataList"
      :auto="false"
      @query="queryList"
    >
      <!-- 内容渲染 -->
    </z-paging>
  </view>
</template>

<script lang="ts" setup>
import { ref, watch } from 'vue'

const tabList = [
  { name: '全部', value: 'all' },
  { name: '进行中', value: 'processing' },
  { name: '已完成', value: 'completed' }
]

const currentTab = ref('all')
const dataList = ref<any[]>([])
const pagingRef = ref()

// Tab切换监听
watch(currentTab, (newVal) => {
  // 切换Tab时重置分页
  pagingRef.value?.reload()
})

const queryList = async (pageNo: number, pageSize: number) => {
  const params = {
    pageNo,
    pageSize,
    status: currentTab.value
  }
  
  const response = await api.getListByStatus(params)
  return {
    data: response.data.list,
    total: response.data.total
  }
}

const tabChange = (index: number) => {
  currentTab.value = tabList[index].value
}
</script>

四、性能优化策略

4.1 数据缓存优化

// 使用Pinia进行分页数据缓存
import { defineStore } from 'pinia'

export const usePagingCache = defineStore('paging-cache', {
  state: () => ({
    cache: new Map<string, any>()
  }),
  
  actions: {
    setCache(key: string, data: any) {
      this.cache.set(key, {
        data,
        timestamp: Date.now()
      })
    },
    
    getCache(key: string, maxAge: number = 5 * 60 * 1000) {
      const cached = this.cache.get(key)
      if (!cached) return null
      
      if (Date.now() - cached.timestamp > maxAge) {
        this.cache.delete(key)
        return null
      }
      
      return cached.data
    }
  }
})

4.2 虚拟列表优化

<template>
  <z-paging
    ref="pagingRef"
    v-model:data="dataList"
    use-virtual-list
    :virtual-list-height="800"
    :virtual-item-size="100"
    @query="queryList"
  >
    <template #default="{ item, index }">
      <view class="virtual-item" :style="{ height: '100px' }">
        <text>{{ item.title }}</text>
      </view>
    </template>
  </z-paging>
</template>

4.3 图片懒加载优化

<template>
  <z-paging
    ref="pagingRef"
    v-model:data="dataList"
    @query="queryList"
  >
    <template #default="{ item }">
      <view class="item">
        <u-image
          :src="item.image"
          mode="aspectFill"
          lazy-load
          :fade="true"
          duration="450"
        />
        <text>{{ item.title }}</text>
      </view>
    </template>
  </z-paging>
</template>

五、常见问题解决方案

5.1 数据重复问题

// 使用Set去重
const handleData = (newData: any[], oldData: any[]) => {
  const combined = [...oldData, ...newData]
  const uniqueData = Array.from(
    new Set(combined.map(item => item.id))
  ).map(id => combined.find(item => item.id === id))
  
  return uniqueData
}

5.2 页码混乱处理

// 防止快速切换导致的页码混乱
let currentPage = 1
let isRequesting = false

const queryList = async (pageNo: number) => {
  if (isRequesting) return
  
  isRequesting = true
  currentPage = pageNo
  
  try {
    const response = await api.getList({ pageNo })
    
    // 检查是否为当前请求的页码
    if (currentPage === pageNo) {
      return {
        data: response.data.list,
        total: response.data.total
      }
    }
  } finally {
    isRequesting = false
  }
}

5.3 错误重试机制

// 带重试机制的分页请求
const queryListWithRetry = async (pageNo: number, retryCount = 3) => {
  for (let i = 0; i < retryCount; i++) {
    try {
      const response = await api.getList({ pageNo })
      return {
        data: response.data.list,
        total: response.data.total
      }
    } catch (error) {
      if (i === retryCount - 1) throw error
      // 等待一段时间后重试
      await new Promise(resolve => setTimeout(resolve, 1000 * (i + 1)))
    }
  }
}

六、最佳实践总结

6.1 配置推荐表

配置项 推荐值 说明
auto false 手动控制加载时机
use-cache true 启用缓存提高性能
hide-empty-view true 自定义空状态显示
loading-more-enabled true 启用上拉加载更多
auto-clean-list-when-reload true 重新加载时清空列表

6.2 性能优化 checklist

  •  启用虚拟列表对于长列表
  •  实现图片懒加载
  •  使用数据缓存机制
  •  优化网络请求频率
  •  合理设置分页大小(建议20-50条)

6.3 错误处理策略

// 统一的错误处理
const handlePagingError = (error: any) => {
  console.error('分页请求错误:', error)
  
  // 网络错误
  if (error.code === 'NETWORK_ERROR') {
    showToast('网络连接失败,请检查网络设置')
  }
  
  // 服务器错误
  else if (error.code >= 500) {
    showToast('服务器繁忙,请稍后重试')
  }
  
  // 其他错误
  else {
    showToast('请求失败,请重试')
  }
  
  // 通知分页组件请求失败
  pagingRef.value?.complete(false)
}

通过本文的深入学习,相信你已经掌握了z-paging在unibest框架中的高级用法。在实际开发中,根据具体业务场景选择合适的配置和优化策略,将大幅提升应用的性能和用户体验。

记得在实践中不断总结经验,形成适合自己的最佳实践方案。Happy coding!

【免费下载链接】unibest unibest - 最好用的 uniapp 开发框架。unibest 是由 uniapp + Vue3 + Ts + Vite5 + UnoCss + WotUI 驱动的跨端快速启动模板,使用 VS Code 开发,具有代码提示、自动格式化、统一配置、代码片段等功能,同时内置了大量平时开发常用的基本组件,开箱即用,让你编写 uniapp 拥有 best 体验。 【免费下载链接】unibest 项目地址: https://gitcode.com/feige996/unibest

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐