在astro.Build中实现自定义选择器过滤数据并跨页保留选中项
在Astro中实现带状态持久化的JSON数据过滤
核心需求拆解
要解决两个核心问题:一是根据自定义选择器的选项过滤JSON数据,二是页面切换/刷新时保留选中的选项状态。下面提供两种实用方案,可根据场景选择。
方案一:用localStorage持久化选中状态
适合不需要分享状态、仅在用户本地保留选择的场景。
1. 组件实现代码
--- // 导入你的JSON数据文件 import countryData from '../data/your-data.json'; --- <div class="filter-container"> <select id="countrySelector"> <option value="">全部国家</option> {countryData.map(item => ( <option key={item.id} value={item.country}>{item.country}</option> ))} </select> <div id="resultsList"> <!-- 初始渲染全部数据 --> {countryData.map(item => ( <div key={item.id} class="result-item"> {item.title} - {item.country} </div> ))} </div> </div> <script is:inline> // 页面加载时读取本地存储的选中状态 const selector = document.getElementById('countrySelector'); const savedSelection = localStorage.getItem('selectedCountry'); if (savedSelection) { selector.value = savedSelection; } // 定义数据过滤与DOM更新函数 function updateFilteredResults(selectedCountry) { const resultsContainer = document.getElementById('resultsList'); const filtered = selectedCountry ? countryData.filter(item => item.country === selectedCountry) : countryData; resultsContainer.innerHTML = filtered.map(item => ` <div key="${item.id}" class="result-item"> ${item.title} - ${item.country} </div> `).join(''); } // 监听选择器变化,保存状态并更新结果 selector.addEventListener('change', (e) => { const selected = e.target.value; localStorage.setItem('selectedCountry', selected); updateFilteredResults(selected); }); // 页面初始化时执行一次过滤,确保状态生效 updateFilteredResults(savedSelection || ''); </script>
2. 关键注意事项
- 客户端脚本需添加
is:inline确保在浏览器端执行; - 多页面复用选择器时,每个页面都要加入读取localStorage和过滤的逻辑,保证状态同步;
- 可通过
storage事件监听其他页面的状态变更,实现跨页自动同步。
方案二:用URL参数传递状态
适合需要分享选择状态、或对SEO友好的场景(服务端可预渲染过滤结果)。
1. 组件实现代码
--- import countryData from '../data/your-data.json'; import { getURL } from 'astro:utils'; // 服务端读取URL查询参数,预过滤数据 const currentURL = new URL(getURL()); const selectedCountry = currentURL.searchParams.get('country') || ''; const preFilteredData = selectedCountry ? countryData.filter(item => item.country === selectedCountry) : countryData; --- <div class="filter-container"> <select id="countrySelector" value={selectedCountry}> <option value="">全部国家</option> {countryData.map(item => ( <option key={item.id} value={item.country}>{item.country}</option> ))} </select> <div id="resultsList"> {preFilteredData.map(item => ( <div key={item.id} class="result-item"> {item.title} - {item.country} </div> ))} </div> </div> <script is:inline> const selector = document.getElementById('countrySelector'); selector.addEventListener('change', (e) => { const selected = e.target.value; const url = new URL(window.location.href); // 更新URL参数 if (selected) { url.searchParams.set('country', selected); } else { url.searchParams.delete('country'); } // 用pushState更新URL而不刷新页面,同时触发过滤 window.history.pushState({}, '', url); updateFilteredResults(selected); }); function updateFilteredResults(selectedCountry) { const resultsContainer = document.getElementById('resultsList'); const filtered = selectedCountry ? countryData.filter(item => item.country === selectedCountry) : countryData; resultsContainer.innerHTML = filtered.map(item => ` <div key="${item.id}" class="result-item"> ${item.title} - ${item.country} </div> `).join(''); } </script>
2. 核心优势
- 状态通过URL传递,页面切换、刷新或分享链接后都能保留选中状态;
- 服务端预渲染过滤后的内容,对SEO更友好;
- 无需依赖本地存储,适合公共场景的状态分享。
通用优化建议
- 若JSON数据量较大,优先用方案二的服务端预过滤,减少客户端计算压力;
- 可将过滤逻辑封装成独立的客户端工具函数,在多个页面复用;
- 选择器样式可自定义,替换为下拉框、单选组等形式,逻辑无需改动。
内容的提问来源于stack exchange,提问作者Davv
相关产品推荐
相关产品推荐

