You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 00:57:04