如何从NFT元数据动态生成无重复值的筛选菜单
动态构建NFT特征筛选菜单方案
核心思路
先批量获取所有NFT元数据,统一处理去重特征,再生成符合要求的嵌套筛选菜单,同时完成藏品渲染。
具体实现步骤
1. 重构异步数据获取逻辑
原循环逐个发起异步请求会导致数据处理顺序混乱,改用Promise.all批量获取所有元数据:
var loopFunction = async function(dataIsLoading) { var itemURI = "https://ikzttp.mypinata.cloud/ipfs/QmQFkLSQysj94s5GvTHPyzTxrawwtjgiiYS2TBLgrvw8CW/"; // 生成所有请求的Promise数组 const dataPromises = []; for (let i = 0; i < 100; i++) { dataPromises.push($.getJSON(itemURI + i)); } // 等待所有请求完成 const allNFTData = await Promise.all(dataPromises); // 处理数据生成筛选菜单和渲染藏品 buildFilterMenu(allNFTData); renderNFTItems(allNFTData); };
2. 构建去重的特征分类对象
用对象存储特征类型,结合Set自动去重特征值:
function buildFilterMenu(nftDataList) { // 存储特征分类:key为trait_type,value为存储唯一值的Set const traitCategories = {}; nftDataList.forEach(data => { data.attributes.forEach(entry => { const traitType = entry.trait_type; // 处理特征值,移除空格和原逻辑保持一致 const traitValue = entry.value.replace(/ /g, ''); if (!traitCategories[traitType]) { traitCategories[traitType] = new Set(); } // 自动去重添加特征值 traitCategories[traitType].add(traitValue); }); }); // 生成筛选菜单HTML结构 let menuHTML = '<ul>'; for (const [traitType, values] of Object.entries(traitCategories)) { menuHTML += `<li> <h2>${traitType}</h2> <ul>`; // 将Set转为数组遍历生成选项 values.forEach(value => { menuHTML += `<li data-trait-type="${traitType}" data-trait-value="${value}">${value}</li>`; }); menuHTML += `</ul></li>`; } menuHTML += '</ul>'; // 将菜单插入页面指定容器(比如添加一个class为filter-menu的容器) $('.filter-menu').html(menuHTML); }
3. 批量渲染NFT藏品
复用原渲染逻辑,整合到批量数据处理流程中:
function renderNFTItems(nftDataList) { let allItemsHTML = ''; nftDataList.forEach((data, index) => { var itemName = data.name; var classes = ""; var traitList = ""; $.each(data.attributes,function(index,entry) { var str = entry.value.replace(/ /g, ''); classes += `${entry.trait_type}${str} `; traitList += `<span class="item-trait-type">${entry.trait_type}:</span> ${str}<br />`; }); let eachItem = `<div class="cstm-grid-item cstm-width-1-2 cstm-width-large-1-3 cstm-width-x-large-1-4 ${classes}" id="${index}"> <div class="img-placeholder"> <img class="lazy" data-src="https://ikzttp.mypinata.cloud/ipfs/QmYDvPAXtiJg7s8JdRBSLWdgSphQdac8j1YuQNNxcGE1hg/${index}.png" width="100%" height="auto" /> </div> <span class="item-title">${itemName}</span> <p class="item-traits">${traitList}</p> </div>`; allItemsHTML += eachItem; }); $('.cstm-grid').html(allItemsHTML); }
4. 绑定筛选功能(可选)
给菜单选项绑定点击事件,通过类名匹配实现藏品筛选:
// 可放在buildFilterMenu函数末尾,或单独绑定事件 $(document).on('click', '.filter-menu li[data-trait-value]', function() { const traitType = $(this).data('trait-type'); const traitValue = $(this).data('trait-value'); const targetClass = `${traitType}${traitValue}`; // 切换选项选中状态 $(this).toggleClass('active'); // 获取所有选中的筛选类名 const activeClasses = $('.filter-menu li.active').map(function() { return `${$(this).data('trait-type')}${$(this).data('trait-value')}`; }).get(); if (activeClasses.length === 0) { // 无选中项时显示所有藏品 $('.cstm-grid-item').show(); } else { // 仅显示包含所有选中类的藏品 $('.cstm-grid-item').hide(); $('.cstm-grid-item').filter(`.${activeClasses.join('.')}`).show(); } });
关键说明
- 用
Promise.all解决异步请求的顺序问题,确保所有元数据获取完成后再处理 - 借助
Set自动去重特征值,无需手动判断重复 - 给筛选选项添加自定义
data-*属性,方便后续绑定筛选逻辑 - 藏品类名与筛选选项一一对应,保证筛选时的精准匹配
内容的提问来源于stack exchange,提问作者JavaScriptLearner
相关产品推荐
相关产品推荐

