基于Vue.js与Rest Countries API的国家搜索栏问题排查
国家信息查询应用问题修复方案
问题诊断
原代码存在以下核心问题导致功能失效:
- Vue3初始化错误:使用
Vue.createApp时保留了Vue2的el选项,未调用.mount()完成挂载,Vue实例未生效 - 异步请求滥用computed:computed属性中使用同步AJAX阻塞页面,且重复请求API,不符合Vue设计规范
- API字段适配错误:Rest Countries API v3的字段结构与v2完全不同,原代码仍使用v2的字段名(如
alpha2Code、flag等) - 缺失HTML模板:未编写对应Vue模板,下拉列表和信息面板无渲染载体
- 搜索过滤逻辑错误:基于v2字段的过滤条件无法匹配v3的响应结构
修复步骤
- 修正Vue3初始化:移除
el选项,调用.mount('#main')完成实例挂载 - 重构数据请求:将API请求移至
created钩子,数据存储在data的countries数组中,computed仅负责搜索过滤 - 适配API v3字段:更新所有字段访问逻辑,比如:
- 国家名称:
country.name.common - 国家代码:
country.cca2(原alpha2Code)、country.cca3(原alpha3Code) - 国旗地址:
country.flags.svg - 语言:遍历
country.languages的value值 - 货币:遍历
country.currencies的value值
- 国家名称:
- 修复搜索过滤:基于v3的
name.common和translations结构调整过滤规则 - 添加HTML模板:实现搜索栏、下拉列表、右侧信息面板的渲染逻辑
完整修复代码
HTML部分
<div id="main"> <div class="search-container"> <input type="text" v-model="search" placeholder="搜索国家..." /> <ul v-if="filteredCountries.length > 0" class="country-list"> <li v-for="country in filteredCountries" :key="country.cca3" @click="selectCountry(country)"> <img :src="country.flags.svg" alt="国旗" width="20" /> {{ country.name.common }} </li> </ul> </div> <section class="country-info" :style="{ backgroundImage: `url(${selectedFlagSrc})` }"> <h2>{{ selectedName }}</h2> <p><strong>国家代码:</strong>{{ selectedCode }}</p> <p><strong>首都:</strong>{{ selectedCapital }}</p> <p><strong>语言:</strong>{{ selectedLanguage }}</p> <p><strong>货币:</strong>{{ selectedCurrency }}</p> <p><strong>经纬度:</strong><a :href="selectedLatlngUrl" target="_blank">{{ selectedLatlng }}</a></p> <p><strong>人口:</strong>{{ selectedPopulation }}</p> <p><strong>面积:</strong>{{ selectedArea }}</p> <p><strong>次区域:</strong>{{ selectedSubregion }}</p> <p><strong>基尼系数:</strong>{{ selectedGini }}</p> <p><strong>时区:</strong>{{ selectedTimezone }}</p> </section> </div>
JavaScript部分
// 数字格式化函数 function formatNumber(labelValue) { const num = Math.abs(Number(labelValue)); if (num >= 1e9) return (num / 1e9).toFixed(2) + 'B'; if (num >= 1e6) return (num / 1e6).toFixed(2) + 'M'; if (num >= 1e3) return (num / 1e3).toFixed(2) + 'K'; return num.toString(); } const app = Vue.createApp({ data() { return { search: '', countries: [], selectedName: '', selectedCode: '', selectedCapital: '', selectedLanguage: '', selectedCurrency: '', selectedLatlng: '', selectedLatlngUrl: '', selectedPopulation: '', selectedArea: '', selectedSubregion: '', selectedGini: '', selectedTimezone: '', selectedFlagSrc: '', }; }, computed: { filteredCountries() { const searchTerm = this.search.toLowerCase(); return this.countries.filter(country => { // 匹配国家名称 const nameMatch = country.name.common.toLowerCase().includes(searchTerm); // 匹配翻译名称 const translationMatch = Object.values(country.translations || {}).some(trans => trans.common.toLowerCase().includes(searchTerm) ); return nameMatch || translationMatch; }); }, }, created() { // 请求国家数据 fetch('https://restcountries.com/v3.1/all') .then(res => res.json()) .then(data => { this.countries = data; // 初始化选中美国 const usCountry = this.countries.find(c => c.cca2 === 'US'); this.selectCountry(usCountry || this.countries[0]); }) .catch(err => console.error('数据请求失败:', err)); }, methods: { selectCountry(country) { const self = this; document.querySelector('section').style.opacity = '0'; setTimeout(() => { self.selectedName = country.name.common || 'N/A'; self.selectedFlagSrc = country.flags.svg || ''; self.selectedCode = `${country.cca2 || 'N/A'} / ${country.cca3 || 'N/A'}`; self.selectedCapital = country.capital?.[0] || 'N/A'; // 处理语言 const languages = country.languages ? Object.values(country.languages) : []; self.selectedLanguage = languages.length > 0 ? languages.join(', ') : 'N/A'; // 处理货币 const currencies = country.currencies ? Object.values(country.currencies).map(c => `${c.name} ${c.symbol}`) : []; self.selectedCurrency = currencies.length > 0 ? currencies.join(', ') : 'N/A'; // 处理经纬度 if (country.latlng?.length === 2) { self.selectedLatlng = `Lat: ${country.latlng[0]}, Lng: ${country.latlng[1]}`; self.selectedLatlngUrl = `https://www.google.com/maps/?q=${country.latlng[0]},${country.latlng[1]}`; } else { self.selectedLatlng = 'N/A'; self.selectedLatlngUrl = ''; } self.selectedPopulation = country.population ? formatNumber(country.population) : 'N/A'; self.selectedArea = country.area ? `${formatNumber(country.area)} km²` : 'N/A'; self.selectedSubregion = country.subregion || 'N/A'; self.selectedGini = country.gini ? Object.values(country.gini)[0] + '%' : 'N/A'; self.selectedTimezone = country.timezones?.join(', ') || 'N/A'; document.querySelector('section').style.opacity = '1'; }, 150); }, }, }); // 挂载Vue实例 app.mount('#main');
样式补充(可选)
.search-container { position: relative; width: 300px; margin: 20px; } .search-container input { width: 100%; padding: 10px; font-size: 16px; } .country-list { position: absolute; top: 100%; left: 0; right: 0; max-height: 300px; overflow-y: auto; border: 1px solid #ccc; background: white; list-style: none; padding: 0; margin: 0; } .country-list li { padding: 8px 12px; cursor: pointer; display: flex; align-items: center; gap: 10px; } .country-list li:hover { background-color: #f0f0f0; } .country-info { margin: 20px; padding: 20px; color: white; background-size: cover; background-position: center; background-color: rgba(0,0,0,0.5); background-blend-mode: darken; border-radius: 8px; max-width: 500px; } .country-info a { color: #42b983; }
修复效果
- 搜索栏输入时实时过滤国家列表,下拉菜单正常展开
- 点击国家后右侧面板平滑切换展示详细信息
- 国旗作为背景图正常显示,信息字段全部适配API v3返回结构
内容的提问来源于stack exchange,提问作者B C
相关产品推荐
相关产品推荐

