在本文中,我将分享如何在 Vue.js 应用中从 API 获取数据,并实现过滤、排序和分页等实用功能。这些功能在处理诸如产品列表或内容库等项目时尤为有用,用户需要一种便捷的方式来浏览数据。我将逐步引导你完成从数据获取到添加交互控件的整个过程,以便你可以在自己的项目中应用这些技术。让我们开始吧!
数据获取
<template> <main class="min-h-screen bg-neutral-200 py-4"> <section class="w-[1280px] mx-auto"> <ul class="mt-1"> <li v-for="product in products" :key="product.id"> {{ product.id }}. {{ product.title }} - ${{ product.price }} - {{ product.category }} </li> </ul> <p v-if="!loading && products.length === 0">暂无数据</p> <p v-if="loading">加载中...</p> <p v-if="error">{{ error }}</p> </section> </main> </template> <script setup lang="ts"> import { onMounted, ref } from'vue'; interface Product { id: number; title: string; price: number; description: string; category: string; image: string; rating: { rate: number; count: number; }; } constBASE_URL = 'https://www.yourdomain.com/products'; const products = ref<Product[]>([]); const loading = ref<boolean>(false); const error = ref<string | null>(null); constfetchProducts = async () => { loading.value = true; try { const response = awaitfetch(BASE_URL); if (!response.ok) { thrownewError(`HTTP 错误! 状态码: ${response.status}`); } products.value = await response.json(); } catch (err) { error.value = err instanceofError ? err.message : '发生未知错误'; } finally { loading.value = false; } }; onMounted(() =>fetchProducts()); </script>
onMounted:
在 Vue.js 中,onMounted
是生命周期钩子之一,它在组件挂载到 DOM 后执行。简单来说,onMounted
中的代码会在组件完全准备好并显示在屏幕上时运行。
在上面的示例中,onMounted
用于在组件加载时调用 fetchProducts
函数。该函数从外部 API 获取产品数据并将其存储在 products
变量中。这确保了用户在查看页面时数据是可用的。它特别适用于初始化数据,例如获取产品列表、文章或页面所需的任何动态信息。
v-for:v-for
是 Vue.js 中的一个指令,用于根据数组或对象中的数据动态渲染元素。在上面的示例中,v-for
用于根据从 API 获取的数据自动生成产品列表。
实现过滤、排序和分页
<template> <main class="min-h-screen bg-neutral-200 py-4"> <section class="w-[1280px] mx-auto"> <div class="flex gap-x-4 items-center"> <input v-model="searchTerm" type="search" placeholder="搜索..." /> <select v-model="category"> <option value="" selected>分类:</option> <option value="men's clothing">男装</option> <option value="women's clothing">女装</option> <option value="jewelery">珠宝</option> <option value="electronics">电子产品</option> </select> <select v-model="sortBy"> <option value="" selected>排序方式:</option> <option value="title">标题</option> <option value="price">价格</option> </select> <select v-model="orderBy"> <option value="" selected>排序顺序:</option> <option value="asc">升序</option> <option value="desc">降序</option> </select> <select v-model="limit"> <option value="" selected>每页显示:</option> <option v-for="index in 20" :value="index">{{ index }}</option> </select> </div> <div class="flex gap-x-4 items-center mt-4"> <button :disabled="page === 1" @click="page > 1 && page--" class="disabled:cursor-not-allowed" > 上一页 </button> <span>第 {{ page }} 页,共 {{ totalPage }} 页</span> <button :disabled="page === totalPage" @click="page < totalPage && page++" class="disabled:cursor-not-allowed" > 下一页 </button> </div> <ul class="mt-1"> <li v-for="product in limitedProducts" :key="product.id"> {{ product.id }}. {{ product.title }} - ${{ product.price }} - {{ product.category }} </li> </ul> <p v-if="!loading && searchedProducts.length === 0">暂无数据</p> <p v-if="loading">加载中...</p> <p v-if="error">{{ error }}</p> </section> </main> </template> <script setup lang="ts"> import { computed, onMounted, ref } from'vue'; interface Product { id: number; title: string; price: number; description: string; category: string; image: string; rating: { rate: number; count: number; }; } constBASE_URL = 'https://www.yourdomain.com/products'; const products = ref<Product[]>([]); const loading = ref<boolean>(false); const error = ref<string | null>(null); const orderBy = ref<string>(''); const category = ref<string>(''); const sortBy = ref<string>(''); const searchTerm = ref<string>(''); const limit = ref<string>(''); const page = ref<number>(1); const totalPage = computed(() => { const itemsPerPage = limit.value ? Number(limit.value) : 10; returnMath.ceil(searchedProducts.value.length / itemsPerPage); }); constfetchProducts = async () => { loading.value = true; try { const response = awaitfetch(BASE_URL); if (!response.ok) { thrownewError(`HTTP 错误! 状态码: ${response.status}`); } products.value = await response.json(); } catch (err) { error.value = err instanceofError ? err.message : '发生未知错误'; } finally { loading.value = false; } }; const orderByProducts = computed(() => { const sortedProducts = [...products.value]; if (sortBy.value === 'title') { return orderBy.value === 'desc' ? sortedProducts.sort((a, b) => b.title.localeCompare(a.title)) : sortedProducts.sort((a, b) => a.title.localeCompare(b.title)); } elseif (sortBy.value === 'price') { return orderBy.value === 'desc' ? sortedProducts.sort((a, b) => b.price - a.price) : sortedProducts.sort((a, b) => a.price - b.price); } elseif (orderBy.value === 'desc') { return sortedProducts.sort((a, b) => b.id - a.id); } return sortedProducts; }); const filteredProducts = computed(() => { if (category.value) { return orderByProducts.value.filter( (product) => product.category === category.value ); } return orderByProducts.value; }); const searchedProducts = computed(() => { if (searchTerm.value) { return filteredProducts.value.filter((product) => product.title .toLocaleLowerCase() .includes(searchTerm.value.toLocaleLowerCase()) ); } return filteredProducts.value; }); const limitedProducts = computed(() => { const itemsPerPage = limit.value ? Number(limit.value) : 10; return searchedProducts.value.slice( (page.value - 1) * itemsPerPage, page.value * itemsPerPage ); }); onMounted(() =>fetchProducts()); </script>
v-model:
Vue 中的 v-model
指令实现了表单输入与其关联的响应式变量之间的双向数据绑定。这意味着输入字段的任何更改都会立即更新链接的变量,而变量的更改也会反映在输入字段中。例如,在此实现中,v-model
与 searchTerm
、category
、sortBy
、orderBy
和 limit
输入一起使用,确保用户的选择或输入动态更新应用程序状态。
computed:computed
属性用于根据应用程序的状态执行响应式计算。它们仅在依赖项更改时重新计算,从而实现高效更新。在此实现中,orderByProducts
、filteredProducts
、searchedProducts
和 limitedProducts
等计算属性实现了产品列表的无缝过滤、排序和分页。每个计算属性都基于前一个的结果,确保所有操作在状态更改时一致且动态地应用。
过滤:
过滤过程检查是否选择了类别。如果选择了类别,则仅包含属于该类别的产品。
排序:
排序逻辑使用 JavaScript 的 sort
方法:
对于标题,使用 localeCompare
进行字符串比较。对于价格,执行数值排序。
分页:slice
方法根据当前页面和选择的限制确定显示哪些产品。例如,如果 limit = 5
且 page = 2
,则显示索引为 5–9 的产品。
结论
感谢你花时间阅读本文。我希望本文能让你清楚地了解如何在 Vue.js 中有效地实现过滤、排序和分页。通过结合 v-model
的数据绑定和 computed
属性的响应式更新,这种方法确保了高效且动态的用户体验。