如何从Marvel API获取全量数据集并实现全局角色搜索
实现漫威角色全局搜索的两种方案
你的核心问题是当前搜索仅过滤已加载的单页数据,要实现全局搜索,有两种可行方案,根据需求选择:
方案一:利用Marvel API自带搜索参数(推荐)
Marvel API的/characters端点支持nameStartsWith参数,可直接返回名称以指定字符串开头的所有角色,由API端处理搜索逻辑,无需拉取全量数据,性能更优。
修改步骤:
- 更新
getMarvelCharacters函数,支持传入搜索参数:
// 新增全局变量存储当前搜索词 let currentSearchTerm = null; const getMarvelCharacters = async function(searchTerm = currentSearchTerm){ currentSearchTerm = searchTerm; // 更新当前搜索状态 const url = `http://gateway.marvel.com/v1/public/characters?` const searchparam = new URLSearchParams({ ts : timestamp, apikey: publicKey, hash:hashVal, limit: resultsPerPage, offset: offset }) // 若有搜索词,添加API搜索参数 if(searchTerm){ searchparam.append('nameStartsWith', searchTerm); } const response = await fetch(url + searchparam) try { if(!response.ok){ throw new Error('network response is not okay') } const data = await response.json() const totalNumOfChar = data.data.total console.log(totalNumOfChar) let characters = data.data.results displayCharacters(characters) console.log(characters) return { characters, total: totalNumOfChar } } catch (error) { console.error('There was an error:', error) } }
- 修改
searchCharacters函数,点击搜索时重置分页并触发带参数的API请求:
const searchCharacters = async function(){ button.addEventListener('click', async (event)=>{ event.preventDefault() const searchTerm = searchInput.value.trim().toLowerCase() // 重置分页状态 currentPage = 1 offset = 0 // 调用带搜索参数的接口 await getMarvelCharacters(searchTerm) }) }
- 分页逻辑自动适配:原有的分页按钮代码无需额外修改,
getMarvelCharacters会自动带上当前搜索词,确保分页仅针对搜索结果。
方案二:本地缓存全量角色数据(支持任意位置包含搜索)
如果需要实现名称任意位置包含的搜索(比如搜man匹配Spider-Man、Iron Man),Marvel API无直接支持参数,需先拉取全量数据到本地缓存,再进行本地过滤。
修改步骤:
- 新增全局变量存储全量数据与状态:
let allCharacters = []; // 存储所有漫威角色 let currentFilteredCharacters = []; // 存储当前搜索过滤结果 let isAllDataLoaded = false; // 标记全量数据是否加载完成
- 新增全量数据拉取函数:
const fetchAllCharacters = async function(){ let total = 0; let currentOffset = 0; allCharacters = []; // 先获取角色总数 const initialUrl = `http://gateway.marvel.com/v1/public/characters?${new URLSearchParams({ ts: timestamp, apikey: publicKey, hash: hashVal, limit: 100 // 每次拉取100条,减少请求次数 })}`; const initialResponse = await fetch(initialUrl); const initialData = await initialResponse.json(); total = initialData.data.total; // 循环拉取所有数据 while(currentOffset < total){ const url = `http://gateway.marvel.com/v1/public/characters?${new URLSearchParams({ ts: timestamp, apikey: publicKey, hash: hashVal, limit: 100, offset: currentOffset })}`; const response = await fetch(url); const data = await response.json(); allCharacters.push(...data.data.results); currentOffset += 100; } isAllDataLoaded = true; console.log('全量角色数据加载完成,共', allCharacters.length, '条'); }
- 更新搜索与分页逻辑:
// 页面加载时启动全量数据拉取 fetchAllCharacters(); const searchCharacters = async function(){ button.addEventListener('click', async (event)=>{ event.preventDefault() const searchTerm = searchInput.value.trim().toLowerCase() currentFilteredCharacters = []; currentPage = 1; if(!searchTerm) { // 搜索词为空,回到全量数据分页展示 offset = 0; getMarvelCharacters(); return; } // 若全量数据未加载,先加载 if(!isAllDataLoaded){ await fetchAllCharacters(); } // 本地过滤全量数据 currentFilteredCharacters = allCharacters.filter(char => char.name.toLowerCase().includes(searchTerm) ); // 展示第一页过滤结果 const startIndex = (currentPage - 1) * resultsPerPage; const pageData = currentFilteredCharacters.slice(startIndex, startIndex + resultsPerPage); displayCharacters(pageData); }) } // 修改分页按钮逻辑,适配搜索结果分页 const getPaginationButtonResults = function(){ const next = document.querySelector('.right') const prev = document.querySelector('.left') next.addEventListener('click', async (event)=>{ event.preventDefault() if(currentFilteredCharacters.length){ // 处于搜索状态,分页过滤结果 const maxPage = Math.ceil(currentFilteredCharacters.length / resultsPerPage); if(currentPage < maxPage){ currentPage++; const startIndex = (currentPage - 1) * resultsPerPage; const pageData = currentFilteredCharacters.slice(startIndex, startIndex + resultsPerPage); displayCharacters(pageData); } } else { // 正常分页全量数据 currentPage++ offset+=resultsPerPage await getMarvelCharacters() } }) prev.addEventListener('click', async (event)=>{ event.preventDefault() if(currentFilteredCharacters.length){ // 处于搜索状态 if(currentPage > 1){ currentPage--; const startIndex = (currentPage - 1) * resultsPerPage; const pageData = currentFilteredCharacters.slice(startIndex, startIndex + resultsPerPage); displayCharacters(pageData); } } else { // 正常分页 currentPage-- if(currentPage>0){ offset-=resultsPerPage await getMarvelCharacters() } } }) }
内容的提问来源于stack exchange,提问作者F Adam
相关产品推荐
相关产品推荐

