制作一个基于星球大战API的比较星舰的web应用程序。
应包括:
当用户单击“比较”按钮时,表将被填充。基于在昏睡控制中选择的选项。
在每一行:高亮显示值较高的单元格。
(() => {
function removeHigherValueClass() {
document.querySelectorAll('.data-cell').forEach((dataCell) => {
dataCell.classList.remove('higher-value');
});
}
function runGen() {
let genObj = gen();
function nextItem(obj) {
if (obj.done) {
return obj.value;
}
// As long as there a further yield
// statements in the generator function ...
obj.value.then((value) => {
nextItem(genObj.next(value));
}).catch((error) => {
console.log(error);
});
}
nextItem(genObj.next()); // Trigger the recursion the first time.
}
function* gen() {
let url = 'https://swapi.co/api/starships/';
let dataCells = document.querySelectorAll('.data-cell');
let json = [];
let oneResponse = yield fetch(
url + document.getElementById('starShipOne').value,
{ mode: 'cors' } );
json.push(yield oneResponse.json());
let twoResponse = yield fetch(
url + document.getElementById('starShipTwo').value,
{ mode: 'cors' } );
json.push(yield twoResponse.json());
dataCells.forEach((dataCell) => {
let key = dataCell.dataset.key; // The more general name ...
// Starship One == 0, Starship Two == 1
for (let i = 0; i < 2; i++) {
document.getElementById(key + i).textContent = json[i][key]; // The general name together with the index gives the concrete ID.
}
if (!isNaN(json[0][key])) { // If it is computable, comparable data ...
if (parseFloat(json[0][key]) > parseFloat(json[1][key])) { // ... then compare the current spec. Class has only to be attached if one value is really higher. No attachment when equal.
document.getElementById(key + 0)
.classList.add('higher-value');
} else if (parseFloat(json[1][key]) > parseFloat(json[0][key])) {
document.getElementById(key + 1)
.classList.add('higher-value');
}
}
});
}
document
.getElementById('compare')
.addEventListener('click', () => {
removeHigherValueClass();
runGen();
});
})();html {
background-color: rgba(245, 245, 245, .5);
}
.higher-value {
background-color: pink;
font-weight: 900;
}
.main-wrap {
max-width: 800px;
margin: 40px auto;
}
.main-nav {
margin: 0 0 30px;
}
.data-cell {
text-align: center;
width: 200px;
}<section>
<div class="main-wrap">
<h3>Select two Starships from the dropdown lists to compare</h3>
<nav class="main-nav">
<select id="starShipOne">
<option value="2" selected="selected">CR90 Corvette</option>
<option value="75">V-wing</option>
<option value="74">Belbullab-22 Starfighter</option>
<option value="65">Jedi Interceptor</option>
<option value="3">Star Destroyer</option>
<option value="59">Trade Fedaration Cruiser</option>
<option value="58">Solar Sailer</option>
<option value="63">Republic Attack Cruiser</option>
<option value="28">A-wing</option>
<option value="29">B-wing</option>
<option value="39">Naboo Fighter</option>
<option value="10">Millenium Falcon</option>
</select>
<select id="starShipTwo">
<option value="2">CR90 Corvette</option>
<option value="75" selected="selected">V-wing</option>
<option value="74">Belbullab-22 Starfighter</option>
<option value="65">Jedi Interceptor</option>
<option value="3">Star Destroyer</option>
<option value="59">Trade Fedaration Cruiser</option>
<option value="58">Solar Sailer</option>
<option value="63">Republic Attack Cruiser</option>
<option value="28">A-wing</option>
<option value="29">B-wing</option>
<option value="39">Naboo Fighter</option>
<option value="10">Millenium Falcon</option>
</select>
<button id="compare">Compare</button>
</nav>
<table border="1">
<tr>
<th></th>
<th>Starship 1</th>
<th>Starship 2</th>
</tr>
<tr>
<td>Name</td>
<!-- 'data-key' will later determine the row.
id='data-key-value[ 0 || 1 ]' determines the cell -->
<td class="data-cell" data-key="name" id="name0"></td>
<td class="data-cell" data-key="name" id="name1"></td>
</tr>
<tr>
<td>Cost</td>
<td class="data-cell" data-key="cost_in_credits" id="cost_in_credits0"></td>
<td class="data-cell" data-key="cost_in_credits" id="cost_in_credits1"></td>
</tr>
<tr>
<td>Speed</td>
<td class="data-cell" data-key="max_atmosphering_speed" id="max_atmosphering_speed0"></td>
<td class="data-cell" data-key="max_atmosphering_speed" id="max_atmosphering_speed1"></td>
</tr>
<tr>
<td>Cargo Size</td>
<td class="data-cell" data-key="cargo_capacity" id="cargo_capacity0"></td>
<td class="data-cell" data-key="cargo_capacity" id="cargo_capacity1"></td>
</tr>
<tr>
<td>Passengers</td>
<td class="data-cell" data-key="passengers" id="passengers0"></td>
<td class="data-cell" data-key="passengers" id="passengers1"></td>
</tr>
</table>
</div>
</section>你认为我的想法是什么,一般的名称-属性和特定的ID?是否有更好的解决办法?那么依赖于HTML-属性是很好的实践吗?
你对总体上的实现有什么看法?
感谢所有提示、建议和评论。
发布于 2018-11-21 23:17:59
我还注意到,可以用const而不是类似let的key来声明一些变量,因为在forEach回调中永远不会重新分配它。
dataCells.forEach((dataCell) => {
const key = dataCell.dataset.key; // The more general name ...您可以将URL抽象到顶部,作为常量(或者在配置文件中)。这样,如果URL发生变化,您可以在一个地方完成,而不必将其与代码混在一起。
const API_URL = 'https://swapi.co/api/starships/';类似地,fetch()的选项可以存储在常量中。
const fetchOptions = {mode: 'cors'};简化问题的另一个选择是使用Promise.all()同时运行两个API请求,然后从每个响应中获取JSON。
const API_URL = 'https://swapi.co/api/starships/';
(() => {
const dataCells = [...document.getElementsByClassName('data-cell')];
const starShipOne = document.getElementById('starShipOne');
const starShipTwo = document.getElementById('starShipTwo');
function removeHigherValueClass() {
dataCells.forEach((dataCell) => {
dataCell.classList.remove('higher-value');
});
}
const fetchOptions = {mode: 'cors'};
function getData() {
const oneResponse = fetch(API_URL + starShipOne.value, fetchOptions);
const twoResponse = fetch(API_URL + starShipTwo.value, fetchOptions);
return Promise.all([oneResponse, twoResponse]);
}
function getJSONFromResponses(responses) {
return Promise.all(responses.map(response => response.json()));
}
function updateDOM(json) {
dataCells.forEach((dataCell, i) => {
const key = dataCell.dataset.key; // The more general name ...
dataCell.textContent = json[i % 2][key];
// Starship One == 0, Starship Two == 1
if (!isNaN(json[0][key])) { // If it is computable, comparable data ...
if (parseFloat(json[i % 2][key]) > parseFloat(json[(i + 1) % 2][key])) { // ... then compare the current spec. Class has only to be attached if one value is really higher. No attachment when equal.
dataCell.classList.add('higher-value');
}
}
});
}
document
.getElementById('compare')
.addEventListener('click', () => {
removeHigherValueClass();
getData().then(getJSONFromResponses).then(updateDOM);
});
})();html {
background-color: rgba(245, 245, 245, .5);
}
.higher-value {
background-color: pink;
font-weight: 900;
}
.main-wrap {
max-width: 800px;
margin: 40px auto;
}
.main-nav {
margin: 0 0 30px;
}
.data-cell {
text-align: center;
width: 200px;
}<section>
<div class="main-wrap">
<h3>Select two Starships from the dropdown lists to compare</h3>
<nav class="main-nav">
<select id="starShipOne">
<option value="2" selected="selected">CR90 Corvette</option>
<option value="75">V-wing</option>
<option value="74">Belbullab-22 Starfighter</option>
<option value="65">Jedi Interceptor</option>
<option value="3">Star Destroyer</option>
<option value="59">Trade Fedaration Cruiser</option>
<option value="58">Solar Sailer</option>
<option value="63">Republic Attack Cruiser</option>
<option value="28">A-wing</option>
<option value="29">B-wing</option>
<option value="39">Naboo Fighter</option>
<option value="10">Millenium Falcon</option>
</select>
<select id="starShipTwo">
<option value="2">CR90 Corvette</option>
<option value="75" selected="selected">V-wing</option>
<option value="74">Belbullab-22 Starfighter</option>
<option value="65">Jedi Interceptor</option>
<option value="3">Star Destroyer</option>
<option value="59">Trade Fedaration Cruiser</option>
<option value="58">Solar Sailer</option>
<option value="63">Republic Attack Cruiser</option>
<option value="28">A-wing</option>
<option value="29">B-wing</option>
<option value="39">Naboo Fighter</option>
<option value="10">Millenium Falcon</option>
</select>
<button id="compare">Compare</button>
</nav>
<table border="1">
<tr>
<th></th>
<th>Starship 1</th>
<th>Starship 2</th>
</tr>
<tr>
<td>Name</td>
<!-- 'data-key' will later determine the row.
id='data-key-value[ 0 || 1 ]' determines the cell -->
<td class="data-cell" data-key="name" id="name0"></td>
<td class="data-cell" data-key="name" id="name1"></td>
</tr>
<tr>
<td>Cost</td>
<td class="data-cell" data-key="cost_in_credits" id="cost_in_credits0"></td>
<td class="data-cell" data-key="cost_in_credits" id="cost_in_credits1"></td>
</tr>
<tr>
<td>Speed</td>
<td class="data-cell" data-key="max_atmosphering_speed" id="max_atmosphering_speed0"></td>
<td class="data-cell" data-key="max_atmosphering_speed" id="max_atmosphering_speed1"></td>
</tr>
<tr>
<td>Cargo Size</td>
<td class="data-cell" data-key="cargo_capacity" id="cargo_capacity0"></td>
<td class="data-cell" data-key="cargo_capacity" id="cargo_capacity1"></td>
</tr>
<tr>
<td>Passengers</td>
<td class="data-cell" data-key="passengers" id="passengers0"></td>
<td class="data-cell" data-key="passengers" id="passengers1"></td>
</tr>
</table>
</div>
</section>我知道这最初是用ecmascript-6标记的,但我已经了解了更多关于ecmascript-2017特性的信息,比如关键字await和async functions,在使用了它们之后,我会意识到,它们可以极大地简化这里的代码。例如,不必使用生成器函数,您可以使其成为一个常规函数(但前面有async关键字),只需在每个异步请求之前添加await:
async function getData() {
const oneResponse = await fetch(API_URL + starShipOne.value, fetchOptions);
const firstJSON = await oneResponse.json();
const twoResponse = await fetch(API_URL + starShipTwo.value, fetchOptions);
const secondJSON = await twoResponse.json();
return [firstJSON, secondJSON];
}然后就不需要在迭代器上调用.next()的代码了。相反,只需调用.then(updateDOM):
getData().then(updateDOM);请参阅使用这些更新重写的代码。
const API_URL = 'https://swapi.co/api/starships/';
(() => {
const dataCells = [...document.getElementsByClassName('data-cell')];
const starShipOne = document.getElementById('starShipOne');
const starShipTwo = document.getElementById('starShipTwo');
function removeHigherValueClass() {
dataCells.forEach((dataCell) => {
dataCell.classList.remove('higher-value');
});
}
const fetchOptions = {mode: 'cors'};
async function getData() {
const oneResponse = await fetch(API_URL + starShipOne.value, fetchOptions);
const firstJSON = await oneResponse.json();
const twoResponse = await fetch(API_URL + starShipTwo.value, fetchOptions);
const secondJSON = await twoResponse.json();
return [firstJSON, secondJSON];
}
function updateDOM(json) {
dataCells.forEach((dataCell, i) => {
const key = dataCell.dataset.key; // The more general name ...
dataCell.textContent = json[i % 2][key];
// Starship One == 0, Starship Two == 1
if (!isNaN(json[0][key])) { // If it is computable, comparable data ...
if (parseFloat(json[i % 2][key]) > parseFloat(json[(i + 1) % 2][key])) { // ... then compare the current spec. Class has only to be attached if one value is really higher. No attachment when equal.
dataCell.classList.add('higher-value');
}
}
});
}
document
.getElementById('compare')
.addEventListener('click', () => {
removeHigherValueClass();
getData().then(updateDOM);
});
})();html {
background-color: rgba(245, 245, 245, .5);
}
.higher-value {
background-color: pink;
font-weight: 900;
}
.main-wrap {
max-width: 800px;
margin: 40px auto;
}
.main-nav {
margin: 0 0 30px;
}
.data-cell {
text-align: center;
width: 200px;
}<section>
<div class="main-wrap">
<h3>Select two Starships from the dropdown lists to compare</h3>
<nav class="main-nav">
<select id="starShipOne">
<option value="2" selected="selected">CR90 Corvette</option>
<option value="75">V-wing</option>
<option value="74">Belbullab-22 Starfighter</option>
<option value="65">Jedi Interceptor</option>
<option value="3">Star Destroyer</option>
<option value="59">Trade Fedaration Cruiser</option>
<option value="58">Solar Sailer</option>
<option value="63">Republic Attack Cruiser</option>
<option value="28">A-wing</option>
<option value="29">B-wing</option>
<option value="39">Naboo Fighter</option>
<option value="10">Millenium Falcon</option>
</select>
<select id="starShipTwo">
<option value="2">CR90 Corvette</option>
<option value="75" selected="selected">V-wing</option>
<option value="74">Belbullab-22 Starfighter</option>
<option value="65">Jedi Interceptor</option>
<option value="3">Star Destroyer</option>
<option value="59">Trade Fedaration Cruiser</option>
<option value="58">Solar Sailer</option>
<option value="63">Republic Attack Cruiser</option>
<option value="28">A-wing</option>
<option value="29">B-wing</option>
<option value="39">Naboo Fighter</option>
<option value="10">Millenium Falcon</option>
</select>
<button id="compare">Compare</button>
</nav>
<table border="1">
<tr>
<th></th>
<th>Starship 1</th>
<th>Starship 2</th>
</tr>
<tr>
<td>Name</td>
<!-- 'data-key' will later determine the row.
id='data-key-value[ 0 || 1 ]' determines the cell -->
<td class="data-cell" data-key="name" id="name0"></td>
<td class="data-cell" data-key="name" id="name1"></td>
</tr>
<tr>
<td>Cost</td>
<td class="data-cell" data-key="cost_in_credits" id="cost_in_credits0"></td>
<td class="data-cell" data-key="cost_in_credits" id="cost_in_credits1"></td>
</tr>
<tr>
<td>Speed</td>
<td class="data-cell" data-key="max_atmosphering_speed" id="max_atmosphering_speed0"></td>
<td class="data-cell" data-key="max_atmosphering_speed" id="max_atmosphering_speed1"></td>
</tr>
<tr>
<td>Cargo Size</td>
<td class="data-cell" data-key="cargo_capacity" id="cargo_capacity0"></td>
<td class="data-cell" data-key="cargo_capacity" id="cargo_capacity1"></td>
</tr>
<tr>
<td>Passengers</td>
<td class="data-cell" data-key="passengers" id="passengers0"></td>
<td class="data-cell" data-key="passengers" id="passengers1"></td>
</tr>
</table>
</div>
</section>https://codereview.stackexchange.com/questions/180798
复制相似问题