在本文中,我将分享如何在 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://fakestoreapi.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://fakestoreapi.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
属性的响应式更新,这种方法确保了高效且动态的用户体验。
如果你有任何建议、问题或反馈,请随时分享!我始终乐于讨论并愿意提供帮助。
GitHub: https://github.com/rfkyalf/vue-api-handling.git
我始终对连接和协作开发 Web 项目充满热情。你可以访问我的作品集网站了解更多关于我的工作和过往项目的信息:https://www.rifkyalfarez.my.id
原文地址:https://dev.to/rifkyalfarez/how-to-fetch-api-and-implement-filtering-sorting-and-pagination-in-vuejs-1cpg
该文章在 2025/1/2 17:20:30 编辑过