是什么导致无法在 keyup 上更新数组

What causes this failure to update an array on keyup

我正在使用普通(原版)JavaScript[=32= 以 HTML table 的形式显示 JSON ].还有一个搜索(过滤器)功能:

class CountriesList {
  constructor() {
    this.apiURL = "https://gist.githubusercontent.com/Goles/3196253/raw/9ca4e7e62ea5ad935bb3580dc0a07d9df033b451/CountryCodes.json";
    this.countries = [];
    this.searchBox = document.querySelector('#searchBox');
    this.stringToMatch = '';
    this.tableRows = '';
  }

  // Get Items
  async getFilteredCountries() {
    const response = await fetch(this.apiURL);
    this.countries = await response.json();
    // If there is a search string, filter results
    this.stringToMatch = this.searchBox.value;
    if (this.stringToMatch.length > 0) {
      this.countries = this.countries.filter(country => {
        return country.name.toLowerCase().includes(this.stringToMatch.toLowerCase()) || country.code.includes(this.stringToMatch.toUpperCase());
      });
    }
  }

  // Render rows
  renderRows(arr, container) {
    let el = document.querySelector(container);
    el.innerHTML += arr.map(function(item) {
      return `<tr>
          <td>${item.name}</td>
          <td class="text-right">${item.code}</td>
       </tr>`
    }).join('');
  }

  async hideLoader() {
    let loader = document.querySelector('.loader');
    const action = this.countries.length > 0 ? 'add' : 'remove';
    loader.classList[action]('d-none');
  }

  async init() {
    await this.getFilteredCountries();
    await this.hideLoader();
    this.searchBox.addEventListener("keyup", this.getFilteredCountries());
    this.renderRows(this.countries, '#countries_table tbody');
  }
}

const countriesList = new CountriesList();
countriesList.init();
.box {
  position: relative;
  min-height: 90vh;
}

.loader {
  border: 4px solid #ccc;
  border-top-color: transparent;
  border-radius: 50%;
  width: 50px;
  height: 50px;
  position: absolute;
  top: 110px;
  left: 50%;
  margin-left: -50px;
  animation: spin 2s linear infinite;
}

@keyframes spin {
  0% { transform: rotate(0deg); }
  100% { transform: rotate(360deg); }
}
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css" rel="stylesheet"/>
<div class="container-fluid">
  <div class="box">
    <div class="search">
      <input class="my-2 form-control" id="searchBox" type="text" placeholder="Search..." value="">
    </div>
    <table class="table" id="countries_table">
      <thead>
        <tr>
          <th>Country</th>
          <th class="text-right">Code</th>
        </tr>
      </thead>
      <tbody>
      </tbody>
    </table>
    <div class="loader"></div>
  </div>
</div>

问题

脚本无法在 keyup 上更新 countries 数组(并且再次呈现 table) .

我做错了什么?

您可能需要在 keyup 上的 getFilteredCountries 之后调用您的 renderRows 函数。

值过滤结束后需要调用renderRows函数(可以在getFilteredCountries函数内部调用)。

我已经更新了代码并放了一张截图。请检查它是否有帮助。

有一些原因导致您的 renderRows 方法没有被调用。第一件事是在添加一个方法作为事件监听器时,你应该像这样写函数名 this.getFilteredCountries 而不是 this.getFilteredCountries()。我在不同的方法中分离了 API 调用,因为它应该只执行一次,并且在过滤时我们可以过滤数组。最主要的是,在使用 Class 时,我们需要绑定方法或使用 ES6 语法,否则所有 class 属性都将是未定义的 。其余部分很简单。我写了一个单独的方法 updateRows() ,它会首先清除 innerHTML 并显示结果。希望这能解决您的问题。

class CountriesList {
  constructor() {
    this.apiURL =
      "https://gist.githubusercontent.com/Goles/3196253/raw/9ca4e7e62ea5ad935bb3580dc0a07d9df033b451/CountryCodes.json";
    this.countries = [];
    this.searchBox = document.querySelector("#searchBox");
    this.stringToMatch = "";
    this.tableRows = "";
  }

  // Get Items
  getFilteredCountries = async () => {
    const response = await fetch(this.apiURL);
    this.countries = await response.json();
    // If there is a search string, filter results
    this.stringToMatch = this.searchBox.value;
    if (this.stringToMatch.length > 0) {
      this.countries = this.countries.filter((country) => {
        return (
          country.name
            .toLowerCase()
            .includes(this.stringToMatch.toLowerCase()) ||
          country.code.includes(this.stringToMatch.toUpperCase())
        );
      });
      this.renderRows(this.countries, "#countries_table tbody");
    }
  };

  // Render rows
  renderRows = (arr, container) => {
    let el = document.querySelector(container);
    el.innerHTML = "";
    el.innerHTML += arr
      .map(function (item) {
        return `<tr>
              <td>${item.name}</td>
              <td class="text-right">${item.code}</td>
           </tr>`;
      })
      .join("");
  };

  hideLoader = async () => {
    let loader = document.querySelector(".loader");
    const action = this.countries.length > 0 ? "add" : "remove";
    loader.classList[action]("d-none");
  };

  init = async () => {
    await this.getFilteredCountries();
    await this.hideLoader();
    this.searchBox.addEventListener("keyup", this.getFilteredCountries);
    this.renderRows(this.countries, "#countries_table tbody");
  };
}

const countriesList = new CountriesList();
countriesList.init();
.box {
  position: relative;
  min-height: 90vh;
}

.loader {
  border: 4px solid #ccc;
  border-top-color: transparent;
  border-radius: 50%;
  width: 50px;
  height: 50px;
  position: absolute;
  top: 110px;
  left: 50%;
  margin-left: -50px;
  animation: spin 2s linear infinite;
}

@keyframes spin {
  0% {
    transform: rotate(0deg);
  }
  100% {
    transform: rotate(360deg);
  }
}
<link
  href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css"
  rel="stylesheet"
/>
<link rel="stylesheet" href="./style.css" />
<div class="container-fluid">
  <div class="box">
    <div class="search">
      <input
        class="my-2 form-control"
        id="searchBox"
        type="text"
        placeholder="Search..."
        value=""
      />
    </div>
    <table class="table" id="countries_table">
      <thead>
        <tr>
          <th>Country</th>
          <th class="text-right">Code</th>
        </tr>
      </thead>
      <tbody></tbody>
    </table>
    <div class="loader"></div>
  </div>
</div>
<script src="./script.js"></script>