是什么导致无法在 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>
我正在使用普通(原版)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>