Vue项目实现页面加载及搜索时获取展示列表数据的方法
问题排查
你现有代码跑不通首屏加载的核心原因有3个:
- 首屏调用
fetchArtists拉到的全量艺术家数据存在了artists字段,但模板里v-for遍历的是result数组,这个数组初始为空,自然首屏啥都不显示 - 写了
filteredResult计算属性但完全没在模板里用到,全量数据逻辑和搜索数据逻辑完全割裂 - 模板里错用了React的
className语法,Vue里绑定静态类名直接写class就行
实现方案
根据数据量大小选一种实现即可,两类场景都能覆盖:
方案1:前端本地过滤(适合总数据量1000条以内的场景,请求少响应快)
首屏只拉一次全量数据存在本地,用户输入搜索词时直接在前端过滤,不用重复发请求,改动最小:
- 删掉多余的
result字段,全量数据统一存在artists数组 - 模板里直接遍历
filteredResult计算属性 - 删掉keyup绑定的搜索请求方法,靠
v-model绑定的searchQuery自动触发计算属性更新 - 修正模板里的类名写法错误
修正后完整代码:
<template> <div class="body"> <div class="searchBar"> <i class="bi bi-search"></i> <input placeholder="Search for artists" type="text" v-model="searchQuery" /> </div> <div class="artists"> <!-- 注意把className改成class,遍历计算属性 --> <div class="artist__list" v-for="artistResult in filteredResult" :key="artistResult.id" > <h4>{{ artistResult.name }}</h4> </div> <!-- 可选:加无结果提示 --> <div v-if="filteredResult.length === 0">暂无匹配艺术家</div> </div> </div> </template> <script> import axios from "axios"; import "./body.css"; export default { data() { return { artists: [], // 存储全量艺术家数据 searchQuery: "", }; }, mounted() { // 首屏拉取全量数据 this.fetchArtists(); }, computed: { filteredResult() { const keyword = this.searchQuery.trim().toLowerCase(); // 搜索词为空直接返回全量 if (!keyword) return this.artists; // 搜索词不为空走前端过滤 return this.artists.filter((item) => item.name.toLowerCase().includes(keyword) ); }, }, methods: { async fetchArtists() { try { const res = await axios.get("http://localhost:3000/artists"); this.artists = res.data; } catch (error) { console.error("拉取艺术家列表失败:", error); } }, }, }; </script>
方案2:接口搜索(适合总数据量很大的场景,靠后端返回匹配结果)
如果数据量太大前端存不下,就保留搜索接口请求,注意处理搜索词清空的场景,避免发多余请求:
- 统一用
result数组作为渲染数据源,首屏拉全量、搜索拉匹配结果都赋值给这个字段 - 给搜索输入加防抖,避免每按一个键就发一次请求(比如用户连续输3个字只发1次请求)
- 搜索词清空时,不用发请求,直接把之前存的全量
artists赋值给result即可
核心改动代码片段:
// 可以引入lodash的防抖方法,不想引依赖也可以自己实现简单防抖 import _ from "lodash"; export default { data() { return { artists: [], // 存首屏拉到的全量数据,清空搜索时复用 result: [], // 页面渲染用的列表 searchQuery: "", }; }, mounted() { this.fetchArtists(); }, watch: { // 监听搜索词变化,防抖300ms触发搜索 searchQuery: { handler: _.debounce(function (newVal) { const keyword = newVal.trim(); // 关键词为空直接展示全量,不发请求 if (!keyword) { this.result = this.artists; return; } // 有关键词再调用搜索接口 this.searchArtist(keyword); }, 300), }, }, methods: { async fetchArtists() { try { const res = await axios.get("http://localhost:3000/artists"); this.artists = res.data; this.result = res.data; // 首屏拉到数据直接赋值给渲染列表 } catch (error) { console.error("拉取艺术家列表失败:", error); } }, async searchArtist(keyword) { try { const res = await axios.get(`http://localhost:3000/artists?q=${keyword}`); this.result = res.data; } catch (error) { console.error("搜索失败:", error); } }, }, }
模板部分记得把v-for的遍历值改回result,把className改成class即可。
小提示:如果用方案2,建议给axios加请求取消逻辑,避免后发的请求比先发的早返回导致结果错乱。
内容的提问来源于stack exchange,提问作者Basta020
相关产品推荐
相关产品推荐

