英文:
JavaScript - counting clicks on array values while presenting them in a nested loop
问题
你想要扩展一个使用localStorage的待办事项应用程序的示例代码。你希望实现一个优先级功能,但目前遇到了一些问题。你的JavaScript代码似乎没有等待点击事件,而是继续执行循环,导致只看到第一个div中的倒数第二个任务和第二个div中的最后一个任务。同时,你在控制台上看到点击次数的记录也有问题。
以下是你的JavaScript代码的翻译部分:
// 大部分是 LogRocket 的代码,除了计数器的声明
const ul = document.querySelector('ul');
const input = document.getElementById('item');
let itemsArray = localStorage.getItem('items') ? JSON.parse(localStorage.getItem('items')) : [];
let counter = [];
itemsArray.forEach(addTask);
function addTask(text) {
const li = document.createElement('li');
li.textContent = text;
ul.appendChild(li);
}
function add() {
itemsArray.push(input.value);
localStorage.setItem('items', JSON.stringify(itemsArray));
addTask(input.value);
input.value = '';
}
function del() {
localStorage.clear();
ul.innerHTML = '';
itemsArray = [];
}
// LogRocket 代码结束,我的代码开始
function prioritize() {
let task1 = document.getElementById("task1");
let task2 = document.getElementById("task2");
let task1span = task1.appendChild(document.createElement("span"));
let task2span = task2.appendChild(document.createElement("span"));
for (let i = 0; i < itemsArray.length; i++) {
counter[i] = 0;
console.log('项目 ' + (i + 1) + ' = ' + counter[i]);
}
for (let j = 0; j < itemsArray.length - 1; j++) {
task1span.textContent = ``;
task1span.textContent = `${itemsArray[j]}`;
task1span.addEventListener("click", function () {
counter[j] += 1;
console.log('项目 ' + (j + 1) + ' = ' + counter[j]);
});
for (let k = 0; k < itemsArray.length; k++) {
task2.textContent = ``;
task2.textContent = `${itemsArray[k]}`;
task2span.addEventListener("click", function () {
counter[k] += 1;
console.log('项目 ' + (k + 1) + ' = ' + counter[k]);
});
}
}
console.log('最终统计');
for (let l = 0; l < itemsArray.length; l++) {
console.log(`项目 ${l + 1} = ${counter[l]}`);
}
}
希望这有助于你解决问题。如果有进一步的问题,请随时提出。
英文:
I am trying to extend some sample code I found in this LogRocket blog article. The code is for a to-do app using localStorage. I want to extend it in the following way:
First, let me explain what I do on paper when I'm trying to decide between choices. Say I have a list of 5 options, maybe places to volunteer for work. I look at the first and second choices and I put a checkmark by the one I prefer. I then compare the first and third choices and put a checkmark by the one I prefer. I then do the first and fourth and first and fifth. Then, I move down to the second choice and compare the second and third, then the second and fourth, then the second and fifth. Then it's the third and fourth and third and fifth, then finally the fourth and fifth. When I'm done I have compared all choices against each other, and the items are ranked from 4 checkmarks down to 0 checkmarks.
This may sound goofy to you, but it works for me. And I want to be able to do it as an extension of the LogRocket code. Regardless of whether it's the best way to prioritize, I just want to know how to implement this particular way of coding.
So below the list of tasks populated by the user is a Prioritize button. Below that I have two empty divs with plus icons next to them. In the code I have an empty Counter array. When the user clicks the Prioritize button the code creates the same number of values in the Counter array as there are to do tasks. Each of those values are set to 0. Next I have a for loop with another for loop nested in that. The for loops are for displaying the tasks to be compared. What should happen when the button is clicked is that the screen displays in the divs the first and second tasks. When the user clicks either of the plus icons next to one of the divs, the value in the counter array at either the first or second index is incremented by 1. Then the second task disappears from the second div and the third task appears, and upon a click the value at either the first or third index of the Counter array is incremented, etc. Once the inner for loop has displayed all other tasks besides the first in the second div, the first task disappears from the first div and the second task appears there, with the remaining tasks looping through in the second div. You can see where it should go from there.
In my current code I have event listeners in the for loops to try to capture the clicks, but the for loop is not waiting for those clicks. Instead, the for loops run completely through so that on the screen I am only seeing the second to last task in the first div and the last task in the second div. I also have console logs to show the number of clicks. To test this out I put in 5 tasks. The click event is currently on the divs themselves. When the screen displayed just the 4th and 5th tasks and I clicked on the 4th task, the code said items 1 through 4 (indexes 0-3) were now 1, and when I clicked the 5th task, it said items 1 through 4 were equal to 2. So instead of incrementing the value at the index of the task that was clicked, it incremented the first four values simultaneously, plus when the fifth value was clicked, it incremented the others but not the fifth itself.
At first I thought the issue might be one of how to pause a for loop until a click occurs, but now I think my whole approach may be wrong. Here is the code at issue:
The HTML (from within the body element):
<!-- LogRocket code -->
<div class="container">
<div class="to-do-app">
<h2>To-do App</h2>
<br>
<input type="text" id="item" placeholder="Enter item...">
<br><br>
<button onclick="add()">Add Item <i class="fa-solid fa-plus"></i></button>
<button onclick="del()">Clear all <i class="fa-solid fa-ban"></i></button>
</div>
<ul class="to-do-list"></ul>
<!-- end of LogRocket code -->
<!-- my code -->
<button onclick="prioritize()">Prioritize</button>
<div id="task1"><i class="fa-solid fa-circle-plus"></i></div>
<div id="task2"><i class="fa-solid fa-circle-plus"></i></div>
</div>
<script src="./script.js"></script>
The CSS:
/* all LogRocket code */
@import url("https://fonts.googleapis.com/css2?family=Asap&display=swap");
* {
padding: 0;
margin: 0;
box-sizing: border-box;
}
body {
width: 100%;
height: 100vh;
background-color: #e0d6e9;
font-family: "Asap", sans-serif;
}
.container {
max-width: 405px;
margin: 137px auto;
padding: 20px;
display: flex;
flex-direction: column;
}
.to-do-app {
width: 100%;
padding: 20px;
border-radius: 5px;
background-color: whitesmoke;
border: 1px solid #d3d3d3;
}
.to-do-app h2 {
padding: 10px;
}
.to-do-app input {
width: 250px;
padding: 5px;
border-radius: 5px;
border: 1px solid #d3d3d3;
}
.to-do-app button {
width: fit-content;
padding: 5px;
cursor: pointer;
border: 1px solid #d3d3d3;
border-radius: 5px;
background-color: whitesmoke;
}
.to-do-app button:hover {
background-color: rgba(0, 0, 0, 0.1);
}
li {
font-size: 1.5rem;
}
.to-do-list {
margin-top: 20px;
margin-right: 5px;
padding: 0 20px 10px 25px;
display: flex;
flex-direction: column;
gap: 15px;
list-style: none;
}
.to-do-list li {
font-size: small;
background-color: whitesmoke;
padding: 20px;
}
JavaScript:
// mostly LogRocket code except for counter declaration
const ul = document.querySelector('ul');
const input = document.getElementById('item');
let itemsArray = localStorage.getItem('items') ? JSON.parse(localStorage.getItem('items')) : [];
let counter = [];
itemsArray.forEach(addTask);
function addTask(text) {
const li = document.createElement('li');
li.textContent = text;
ul.appendChild(li);
}
function add() {
itemsArray.push(input.value);
localStorage.setItem('items', JSON.stringify(itemsArray));
addTask(input.value);
input.value = '';
}
function del() {
localStorage.clear();
ul.innerHTML = '';
itemsArray = [];
}
// end of LogRocket code and beginning of my code
function prioritize() {
let task1 = document.getElementById("task1");
let task2 = document.getElementById("task2");
let task1span = task1.appendChild(document.createElement("span"));
let task2span = task2.appendChild(document.createElement("span"));
for (let i = 0; i < itemsArray.length; i++) {
counter[i] = 0;
console.log('Item ' + (i + 1) + ' = ' + counter[i]);
}
for (let j = 0; j < itemsArray.length-1; j++) {
task1span.textContent = ``;
task1span.textContent = `${itemsArray[j]}`;
task1span.addEventListener("click", function () {
counter[j] += 1;
console.log('Item ' + (j + 1) + ' = ' + counter[j]);
});
for (let k = 0; k < itemsArray.length; k++) {
task2.textContent = ``;
task2.textContent = `${itemsArray[k]}`;
task2span.addEventListener("click", function () {
counter[k] += 1;
console.log('Item ' + (k + 1) + ' = ' + counter[k]);
});
}
}
console.log('Final tally');
for (let l = 0; l < itemsArray.length; l++) {
console.log(`Item ${l + 1} = ${counter[l]}`);
}
}
Any help is appreciated.
答案1
得分: 0
以下是翻译好的部分:
你想要比较所有的配对,并让用户选择赢家。最后,你希望按获胜次数排序吗?
以下是一种简化的做法。
const list = ["任务1", "任务2", "任务3", "任务4"];
const taskContainer = document.getElementById("taskContainer");
const counter = new Array(list.length).fill(0);
function showAllPairs() {
taskContainer.innerHTML = "";
for (let i = 0; i < list.length - 1; i++) {
for (let j = i + 1; j < list.length; j++) {
taskContainer.innerHTML += `
<div class="pair active">
<div class="item">
<p><button onclick="incrementCounter(this, ${i})">+<\/button> ${list[i]}<\/p>
<\/div>
<div class="item">
<p><button onclick="incrementCounter(this, ${j})">+<\/button> ${list[j]}<\/p>
<\/div>
<\/div>
`;
}
}
}
function incrementCounter(elem, index) {
counter[index]++;
elem.closest(".pair").classList.remove("active");
console.log("" + list + " = " + counter);
}
showAllPairs();
.pair {
display: none;
}
.pair.active {
display: flex;
}
.item {
padding: 5px 20px;
}
让我们优先处理4个任务
<div id="taskContainer"></div>
英文:
Do you want to compare all pairs, letting the user pick the winner. In the end you want to sort it by number of wins?
Here's a simplified way of doing that.
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
const list = ["Task 1", "Task 2", "Task 3", "Task 4"];
const taskContainer = document.getElementById("taskContainer");
const counter = new Array(list.length).fill(0);
function showAllPairs() {
taskContainer.innerHTML = "";
for (let i = 0; i < list.length - 1; i++) {
for (let j = i + 1; j < list.length; j++) {
taskContainer.innerHTML += `
<div class="pair active">
<div class="item">
<p><button onclick="incrementCounter(this, ${i})">+</button> ${list[i]}</p>
</div>
<div class="item">
<p><button onclick="incrementCounter(this, ${j})">+</button> ${list[j]}</p>
</div>
</div>
`;
}
}
}
function incrementCounter(elem, index) {
counter[index]++;
elem.closest(".pair").classList.remove("active");
console.log("" + list + " = " + counter)
}
showAllPairs();
<!-- language: lang-css -->
.pair {
display: none;
}
.pair.active {
display: flex;
}
.item {
padding: 5px 20px;
}
<!-- language: lang-html -->
Let's priortize 4 tasks
<div id="taskContainer"></div>
<!-- end snippet -->
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论