我做了一个小测验,在那里你会得到一个随机的问题,你必须猜测它来自哪个StackExchange站点。
const optionsCount = 6;
const sitesURL = 'https://api.stackexchange.com/2.2/sites?pagesize=999&filter=!SmNU3t0u7kg0gEzR5B';
const questionsURL = 'https://api.stackexchange.com/2.2/questions?page=1&pagesize=100&order=desc&sort=votes&filter=!bA1d_Kvv2YPQWk';
let game = {
questionReady: false,
question: {},
options: [],
answer: 0,
questionsAnswered: 0,
questionsCorrect: 0,
sites: []
}
let elements = {
stats: null,
question: null,
options: [],
next: null
}
document.addEventListener('DOMContentLoaded', init);
function init() {
elements.stats = document.getElementById('stats');
elements.question = document.getElementById('question');
elements.next = document.getElementById('next');
let answers = document.getElementById('answers');
for(let i = 0; i < optionsCount; i++) {
let button = document.createElement('button');
button.addEventListener('click', makeGuess.bind(null, i));
answers.appendChild(button);
elements.options.push(button);
}
loadSites().then(chooseQuestion);
}
function loadSites() {
return fetch(sitesURL)
.then(response => response.json())
.then(data => {
game.sites = data.items.filter(e => e.site_type === "main_site");
})
}
function loadQuestions(index) {
return fetch(questionsURL + '&site=' + game.sites[index].api_site_parameter)
.then(response => response.json())
.then(data => {
game.sites[index].questions = data.items;
})
}
async function chooseQuestion() {
game.options = getOptions(optionsCount, game.sites.length);
game.answer = randInt(optionsCount);
game.question = await getQuestion(game.options[game.answer]);
updateView();
game.questionReady = true;
}
function getOptions(amount, max) {
let options = [];
while(options.length < amount) {
let value = randInt(max);
if(!options.includes(value)) {
options.push(value);
}
}
return options;
}
function randInt(limit) {
return Math.floor(Math.random() * limit);
}
async function getQuestion(index) {
if(!game.sites[index].questions) {
await loadQuestions(index);
}
let size = game.sites[index].questions.length;
return game.sites[index].questions[randInt(size)];
}
function updateView() {
elements.question.innerHTML = game.question.title;
for(let i = 0; i < optionsCount; i++) {
elements.options[i].innerHTML = game.sites[game.options[i]].name;
}
}
function makeGuess(guess) {
if(game.questionReady) {
game.questionsAnswered++;
if(guess === game.answer) {
game.questionsCorrect++;
}
else {
elements.options[guess].classList.add('wrong');
}
elements.options[game.answer].classList.add('correct');
elements.next.disabled = false;
elements.question.setAttribute('href', game.question.link);
let percent = Math.round(100 * game.questionsCorrect / game.questionsAnswered);
elements.stats.innerText = `${game.questionsCorrect}/${game.questionsAnswered} - ${percent}%`;
game.questionReady = false;
}
}
function onNextClick() {
elements.question.removeAttribute('href');
for(option of elements.options) {
option.classList.remove('correct', 'wrong');
}
elements.next.disabled = true;
chooseQuestion();
}.correct {
background-color: #54da54;
}
.wrong {
background-color: #ff6565;
}
#answers button {
margin: 2px;
}0/0 - 0%
Next question如果你喜欢摆弄的话,这里有一个JSFiddle。
它应该能在所有的现代浏览器中工作。我尝试在可能的情况下利用一些新的javaScript特性。我想知道我是否能使代码更好,比如使用最佳实践、可读性、效率等等。
发布于 2018-06-09 20:25:42
下面是一些关于我注意到的一些事情的快速评论。
考虑将代码包装在立即调用的函数表达式中。这将防止页面上的其他代码(意外)与您的代码交互。
在下面的循环中,您将在全局命名空间中删除option。使用const option of elements.options代替:
for(option of elements.options) {
option.classList.remove('correct', 'wrong');
}考虑更多地使用const。如果您不打算重新赋值一个变量,声明它const将提醒您您正在做一些您在过去不打算做的事情。它还可能提高性能。
您的代码缺少错误处理。特别是,如果api调用失败,您的代码将在let size = game.sites[index].questions.length;行上失败。抓住错误并相应地做些事情。
不要在html元素上使用onclick或其任何兄弟节点作为属性。(实际上,也不要在javascript中使用它),请使用addEventListener,就像您已经为其他按钮所做的那样。
https://codereview.stackexchange.com/questions/196170
复制相似问题