Vue3 分页组件封装方法与使用指南详解

# Vue3 分页组件使用指南与封装方法

## 一、基础使用方法

### 1. 安装依赖

确保项目中已安装 Vue3 和 Tailwind CSS:

```bash

npm install vue@3 tailwindcss@latest

```

### 2. 创建分页组件

将前面示例代码保存为 `Pagination.vue` 文件:

```javascript

// Pagination.vue

<template>

  <div class="container mx-auto px-4 py-8">

    <!-- 数据列表 -->

    <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6 mb-8">

      <div class="bg-white rounded-lg shadow-md p-6" v-for="item in currentPageData" :key="item.id">

        <h3 class="text-xl font-semibold mb-2">{{ item.title }}</h3>

        <p class="text-gray-600">{{ item.content }}</p>

      </div>

    </div>


    <!-- 分页导航 -->

    <div class="flex justify-center items-center space-x-2">

      <button

        @click="prevPage"

        :disabled="currentPage === 1"

        class="px-4 py-2 bg-gray-200 hover:bg-gray-300 rounded-md transition-colors duration-200"

      >

        上一页

      </button>


      <!-- 页码列表 -->

      <div class="flex space-x-1">

        <button

          v-for="page in visiblePages"

          :key="page"

          :class="page === currentPage ? 'bg-primary text-white' : 'bg-gray-200 hover:bg-gray-300'"

          @click="goToPage(page)"

          class="w-10 h-10 flex items-center justify-center rounded-md transition-colors duration-200"

        >

          {{ page }}

        </button>

      </div>


      <button

        @click="nextPage"

        :disabled="currentPage === totalPages"

        class="px-4 py-2 bg-gray-200 hover:bg-gray-300 rounded-md transition-colors duration-200"

      >

        下一页

      </button>

    </div>

  </div>

</template>

<script setup>

import { ref, computed } from 'vue';

// 模拟数据

const mockData = Array.from({ length: 50 }, (_, i) => ({

  id: i + 1,

  title: `文章标题 ${i + 1}`,

  content: `这是文章 ${i + 1} 的内容描述...`

}));

// 分页状态

const currentPage = ref(1);

const itemsPerPage = ref(10);

// 计算属性

const totalItems = computed(() => mockData.length);

const totalPages = computed(() => Math.ceil(totalItems.value / itemsPerPage.value));

// 当前页数据

const currentPageData = computed(() => {

  const startIndex = (currentPage.value - 1) * itemsPerPage.value;

  const endIndex = startIndex + itemsPerPage.value;

  return mockData.slice(startIndex, endIndex);

});

// 可见页码范围

const visiblePages = computed(() => {

  let startPage = Math.max(1, currentPage.value - 2);

  let endPage = Math.min(totalPages.value, startPage + 4);


  if (endPage - startPage < 4) {

    startPage = Math.max(1, endPage - 4);

  }


  return Array.from({ length: endPage - startPage + 1 }, (_, i) => startPage + i);

});

// 分页操作

const goToPage = (page) => {

  if (page >= 1 && page <= totalPages.value) {

    currentPage.value = page;

  }

};

const prevPage = () => {

  if (currentPage.value > 1) {

    currentPage.value--;

  }

};

const nextPage = () => {

  if (currentPage.value < totalPages.value) {

    currentPage.value++;

  }

};

</script>

<style scoped>

.primary {

  background-color: #3b82f6;

}

</style>

```

### 3. 在页面中使用

在需要分页功能的组件中引入并使用:

```javascript

<template>

  <div>

    <h1 class="text-2xl font-bold mb-6">文章列表</h1>

    <Pagination />

  </div>

</template>

<script setup>

import Pagination from './Pagination.vue';

</script>

```

## 二、组件封装方法

### 1. 提取props使组件可复用

将数据和分页配置作为 props 传入,使组件可以在不同场景复用:

```javascript

// Pagination.vue

<template>

  <div class="container mx-auto px-4 py-8">

    <!-- 数据列表 -->

    <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6 mb-8">

      <div class="bg-white rounded-lg shadow-md p-6" v-for="item in currentPageData" :key="item.id">

        <h3 class="text-xl font-semibold mb-2">{{ item.title }}</h3>

        <p class="text-gray-600">{{ item.content }}</p>

      </div>

    </div>


    <!-- 分页导航 -->

    <div class="flex justify-center items-center space-x-2">

      <button

        @click="prevPage"

        :disabled="currentPage === 1"

        class="px-4 py-2 bg-gray-200 hover:bg-gray-300 rounded-md transition-colors duration-200"

      >

        上一页

      </button>


      <!-- 页码列表 -->

      <div class="flex space-x-1">

        <button

          v-for="page in visiblePages"

          :key="page"

          :class="page === currentPage ? 'bg-primary text-white' : 'bg-gray-200 hover:bg-gray-300'"

          @click="goToPage(page)"

          class="w-10 h-10 flex items-center justify-center rounded-md transition-colors duration-200"

        >

          {{ page }}

        </button>

      </div>


      <button

        @click="nextPage"

        :disabled="currentPage === totalPages"

        class="px-4 py-2 bg-gray-200 hover:bg-gray-300 rounded-md transition-colors duration-200"

      >

        下一页

      </button>

    </div>

  </div>

</template>

<script setup>

import { ref, computed, defineProps, defineEmits } from 'vue';

const props = defineProps({

  data: {

    type: Array,

    required: true

  },

  itemsPerPage: {

    type: Number,

    default: 10

  },

  initialPage: {

    type: Number,

    default: 1

  }

});

// 分页状态

const currentPage = ref(props.initialPage);

// 计算属性

const totalItems = computed(() => props.data.length);

const totalPages = computed(() => Math.ceil(totalItems.value / props.itemsPerPage));

// 当前页数据

const currentPageData = computed(() => {

  const startIndex = (currentPage.value - 1) * props.itemsPerPage;

  const endIndex = startIndex + props.itemsPerPage;

  return props.data.slice(startIndex, endIndex);

});

// 可见页码范围

const visiblePages = computed(() => {

  let startPage = Math.max(1, currentPage.value - 2);

  let endPage = Math.min(totalPages.value, startPage + 4);


  if (endPage - startPage < 4) {

    startPage = Math.max(1, endPage - 4);

  }


  return Array.from({ length: endPage - startPage + 1 }, (_, i) => startPage + i);

});

// 分页操作

const goToPage = (page) => {

  if (page >= 1 && page <= totalPages.value) {

    currentPage.value = page;

  }

};

const prevPage = () => {

  if (currentPage.value > 1) {

    currentPage.value--;

  }

};

const nextPage = () => {

  if (currentPage.value < totalPages.value) {

    currentPage.value++;

  }

};

</script>

<style scoped>

.primary {

  background-color: #3b82f6;

}

</style>

```

### 2. 添加事件回调

添加页码变化时的回调事件,便于父组件处理:

```javascript

// 新增emits定义

const emits = defineEmits(['page-change']);

// 在页码变化时触发事件

const goToPage = (page) => {

  if (page >= 1 && page <= totalPages.value) {

    currentPage.value = page;

    emits('page-change', page); // 触发页码变化事件

  }

};

// 同样处理prevPage和nextPage方法

const prevPage = () => {

  if (currentPage.value > 1) {

    currentPage.value--;

    emits('page-change', currentPage.value);

  }

};

```

### 3. 使用插槽自定义内容

添加插槽使列表内容可以自定义:

```javascript

<template>

  <div class="container mx-auto px-4 py-8">

    <!-- 使用插槽显示数据 -->

    <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6 mb-8">

      <slot name="item" v-for="item in currentPageData" :item="item" :key="item.id">

        <!-- 默认内容 -->

        <div class="bg-white rounded-lg shadow-md p-6">

          <h3 class="text-xl font-semibold mb-2">{{ item.title }}</h3>

          <p class="text-gray-600">{{ item.content }}</p>

        </div>

      </slot>

    </div>


    <!-- 分页导航 -->

    <div class="flex justify-center items-center space-x-2">

      <!-- 导航代码保持不变 -->

    </div>

  </div>

</template>

```

## 三、高级使用示例

### 1. 使用封装后的分页组件

```javascript

<template>

  <div>

    <h1 class="text-2xl font-bold mb-6">商品列表</h1>


    <Pagination :data="products" :items-per-page="6">

      <template #item="{ item }">

        <div class="bg-white rounded-lg shadow-md overflow-hidden transition-transform duration-300 hover:scale-[1.02]">

          <img :src="item.image" alt="商品图片" class="w-full h-48 object-cover">

          <div class="p-4">

            <h3 class="text-lg font-semibold mb-1">{{ item.name }}</h3>

            <p class="text-gray-600 text-sm mb-2">{{ item.description }}</p>

            <div class="flex justify-between items-center">

              <span class="text-primary font-bold">¥{{ item.price }}</span>

              <button class="bg-primary hover:bg-primary/90 text-white px-3 py-1 rounded text-sm transition-colors">

                加入购物车

              </button>

            </div>

          </div>

        </div>

      </template>

    </Pagination>

  </div>

</template>

<script setup>

import { ref, onMounted } from 'vue';

import Pagination from './Pagination.vue';

const products = ref([]);

onMounted(() => {

  // 模拟从API获取商品数据

  fetchProducts().then(data => {

    products.value = data;

  });

});

const fetchProducts = async () => {

  // 实际项目中这里会是API调用

  return [

    { id: 1, name: '商品1', price: 99.9, description: '这是一个很棒的商品', image: 'https://picsum.photos/200/300?random=1' },

    { id: 2, name: '商品2', price: 199.9, description: '高质量产品', image: 'https://picsum.photos/200/300?random=2' },

    // 更多商品...

  ];

};

</script>

```

### 2. 监听页码变化事件

```javascript

<Pagination

  :data="products"

  :items-per-page="6"

  @page-change="handlePageChange"

/>

<script setup>

const handlePageChange = (page) => {

  console.log('当前页码:', page);

  // 可以在这里添加页面滚动到顶部等逻辑

  window.scrollTo({ top: 0, behavior: 'smooth' });

};

</script>

```

## 四、自定义配置选项

### 1. 样式配置

可以通过 props 传递自定义类名:

```javascript

// 在组件中添加props

const props = defineProps({

  // 其他props保持不变

  pageBtnClass: {

    type: String,

    default: 'w-10 h-10 flex items-center justify-center rounded-md transition-colors duration-200'

  },

  activeBtnClass: {

    type: String,

    default: 'bg-primary text-white'

  },

  inactiveBtnClass: {

    type: String,

    default: 'bg-gray-200 hover:bg-gray-300'

  }

});

// 在模板中使用

<button

  v-for="page in visiblePages"

  :key="page"

  :class="[props.pageBtnClass, page === currentPage ? props.activeBtnClass : props.inactiveBtnClass]"

  @click="goToPage(page)"

>

  {{ page }}

</button>

```

### 2. 页码显示范围配置

```javascript

// 添加props

visibleRange: {

  type: Number,

  default: 2 // 左右显示的页码数量

}

// 更新计算属性

const visiblePages = computed(() => {

  let startPage = Math.max(1, currentPage.value - props.visibleRange);

  let endPage = Math.min(totalPages.value, startPage + props.visibleRange * 2);


  if (endPage - startPage < props.visibleRange * 2) {

    startPage = Math.max(1, endPage - props.visibleRange * 2);

  }


  return Array.from({ length: endPage - startPage + 1 }, (_, i) => startPage + i);

});

```

## 五、最佳实践建议

1. **保持组件单一职责**:分页组件只负责分页逻辑,数据获取和渲染由父组件处理

2. **使用provide/inject**:对于大型应用,可以使用 Vue 的 provide/inject 机制提供全局分页配置

3. **添加过渡动画**:使用 Vue 的 transition 组件为页面切换添加平滑过渡效果

4. **考虑无障碍性**:为分页按钮添加 aria-label 属性,提高屏幕阅读器的可用性

5. **单元测试**:为分页逻辑编写单元测试,确保各种边界条件下的正确性

通过以上封装方法,你可以创建一个高度可复用、灵活配置的分页组件,满足各种前端分页需求。


---

Vue3, 分页组件,组件封装,前端开发,JavaScript,Vue 组件,分页功能,前端框架,Web 开发,组件化开发,前端组件,Vue.js, 分页插件,前端技术,热门组件


---



---

资源地址:

[https://pan.quark.cn/s/50438c9ee7c0](https://pan.quark.cn/s/50438c9ee7c0)


---

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

友情链接更多精彩内容