Javascript 难以将唯一事件侦听器添加到已创建的<;部门>;通过for循环的元素
我正在进行一个学习JavaScript的项目,目标是在一个单页web应用程序中动态地提供电子邮件。应用程序的HTML是使用createElement JS方法创建的。到目前为止,我已成功显示“收件箱”页面,其中包含所有电子邮件,如下图所示: 我目前正试图通过使用addEventListener使这些单独的电子邮件都可以点击。我遇到的问题是,每当我单击任何电子邮件时,收件箱中的第一封电子邮件(id:1,主题:测试电子邮件)都会被呈现出来,并且无法查看任何其他电子邮件 我可以看到,对于所有创建的div,都将相同的email.id应用于事件侦听器,尽管所有div都已正确创建,所有信息都来自相应的电子邮件 下面是load mailbox JS,它呈现收件箱中的所有电子邮件:Javascript 难以将唯一事件侦听器添加到已创建的<;部门>;通过for循环的元素,javascript,html,Javascript,Html,我正在进行一个学习JavaScript的项目,目标是在一个单页web应用程序中动态地提供电子邮件。应用程序的HTML是使用createElement JS方法创建的。到目前为止,我已成功显示“收件箱”页面,其中包含所有电子邮件,如下图所示: 我目前正试图通过使用addEventListener使这些单独的电子邮件都可以点击。我遇到的问题是,每当我单击任何电子邮件时,收件箱中的第一封电子邮件(id:1,主题:测试电子邮件)都会被呈现出来,并且无法查看任何其他电子邮件 我可以看到,对于所有创建的
function load_mailbox(mailbox) {
// Show the mailbox and hide other views
document.querySelector('#emails-view').style.display = 'block';
document.querySelector('#compose-view').style.display = 'none';
document.querySelector('#single-view').style.display = 'none';
// Show the mailbox name
document.querySelector('#emails-view').innerHTML = `<h3>${mailbox.charAt(0).toUpperCase() + mailbox.slice(1)}</h3>`;
// GET request
fetch(`/emails/${mailbox}`)
.then(response => response.json())
.then(emails => {
// Print emails to console
console.log(emails);
// Iterate through each email
for(var i = 0; i < emails.length; i++) {
var email = emails[i];
// Create div and append email content to HTML
var emaildiv = document.createElement('div');
emaildiv.style.borderStyle = 'solid';
emaildiv.style.borderColor = 'black';
emaildiv.style.borderWidth = '0.1rem';
emaildiv.style.borderRadius = '0';
emaildiv.style.marginBottom = '0.2rem';
emaildiv.style.padding = '0.3rem';
emaildiv.innerHTML = `<b>${email.sender}</b> --- ${email.subject}<br>${email.timestamp}`;
// If individual email selected then view email
emaildiv.addEventListener('click', () => view_email(email));
// Populate div HTML with emails
document.querySelector('#emails-view').append(emaildiv);
console.log(email.read);
// Colour backgrounds based on whether emails have been read
if (email.read == true) {
emaildiv.style.backgroundColor = 'lightgrey';
}
console.log(email);
}
});}
我已经试着将其他每封电子邮件的id硬编码到view email JS中,并且可以看到功能按要求工作(显示电子邮件)
因此,我知道问题与上面的load mailbox JS有关,并且可能与for循环中如何应用事件侦听器有关。如果有人能对如何将一个独特的事件监听器应用于每个div有所启发,那将是非常感谢的
谢谢大家! 您的问题在于在循环中声明电子邮件的方式:
var email = emails[i];
由于作用域,您可以围绕email
创建一个闭包,循环的所有迭代都使用一个值。对于块级范围,将其更改为let
,以便每个循环迭代都可以使用自己的值:
let email = emails[i];
其他:
为了使代码更易于阅读和维护,请不要设置内联样式。而是创建CSS类,并根据需要应用/删除这些类。因此,不是:
document.querySelector('#emails-view').style.display = 'none';
document.querySelector('#compose-view').style.display = 'none';
document.querySelector('#single-view').style.display = 'block';
只需创建一个名为.hidden
的CSS类,如下所示:
.hidden { display:none; }
.readEmail {
border: 0.1rem solid black;
border-radius: 0;
margin-bottom: 0.2rem;
padding: 0.3rem;
}
emaildiv.addEventListener('click', () => view_email(email.id));
并且,当元素需要该类或需要删除该类时,请执行以下操作:
someElement.classList.add("hidden");
someElement.classList.remove("hidden");
同样,与此相反:
// Create div, set class, and append email content to HTML
var reademail = document.createElement('div');
reademail.innerHTML = '';
reademail.style.borderStyle = 'solid';
reademail.style.borderColor = 'black';
reademail.style.borderWidth = '0.1rem';
reademail.style.borderRadius = '0';
reademail.style.marginBottom = '0.2rem';
reademail.style.padding = '0.3rem';
创建一个CSS类,如下所示:
.hidden { display:none; }
.readEmail {
border: 0.1rem solid black;
border-radius: 0;
margin-bottom: 0.2rem;
padding: 0.3rem;
}
emaildiv.addEventListener('click', () => view_email(email.id));
然后将其添加到新元素中(另外,当字符串不包含任何HTML时,不要使用.innerHTML
,因为.innerHTML
具有安全性和性能含义):
在emaildiv.addEventListener中('click',()=>查看电子邮件(email))进入
load_mailbox
功能,您正在为每个循环中更改的email
对象分配引用。
因为在view\u email
功能中,您只需要电子邮件的id,我建议您只将email.id
参数传递给此功能,如下所示:
.hidden { display:none; }
.readEmail {
border: 0.1rem solid black;
border-radius: 0;
margin-bottom: 0.2rem;
padding: 0.3rem;
}
emaildiv.addEventListener('click', () => view_email(email.id));
email.id
是一个基本值(一个数字),Javascript作为值而不是引用传递。因此,查看电子邮件
功能变成:
// View email
function view_email(emailId) {
console.log(emailId);
...
// GET request
fetch(`/emails/${emailId}`)
.then(response => response.json())
.then(email => {
...
});
}
你在console.log(电子邮件)中看到了什么代码>,作为对象的电子邮件列表,具有不同的ID?在
console.log(email.id)中可以看到相同的id代码>在你的加载函数中?嗨@BrightFaith-是的,没错。:)我找不到问题所在,但如果我写这篇文章,我会使用data attribute=“”
,将id
作为自定义属性
分配给元素,然后为文档
编写一个全局单击事件侦听器,检查e.target
是否是我的电子邮件元素之一,然后使用JS的getAttribute
方法获取它的属性,并传递给加载函数谢谢您为我查看,并提供建议!感谢Scott的解决方案和解释,这为我解决了问题-非常感谢您的帮助!非常感谢您提供了额外的注释,我们将回顾并在中添加这些更改-我之前一直在尝试如何添加类,但似乎没有任何效果。将给出类列表。现在添加一个go。非常感谢你的帮助!:)通常,将引用传递给元素比传递给元素的属性更好,因此OP现在这样做的方式确实是最好的。原因是,如果只传递一个属性的值,然后函数需要其他属性的值,那么必须重新获取对元素的引用(在循环中这可能会有问题)。如果向元素传递引用,则接收方可以非常轻松地访问任何/所有属性值。另外,email.id
不是一个数字,而是一个字符串。因此,为了说明这一点,如果OP采纳了您的建议并传递了email.id
,那么查看电子邮件
功能在到达以下位置时会遇到问题:(email=>
因为对email
元素的引用不会被传递。@ScottMarcus在Tjm92发布的JSON中(我想这是一个email对象),包含在id
属性中的值是一个数字(示例中为1)另外,我认为函数view\u email
与paramemail
没有任何问题,因为函数本身会新获取电子邮件,然后在中获取email
(email=>
是fetch
的JSON,你对email.id
的看法是正确的(我没有看到问题中的JSON),但是查看\u email
并没有获取email
。它使用email
来获取id
。而且,在您的建议中,您甚至没有email
可供使用。不管怎样,我的原始观点仍然是,最好传递对DOM元素的引用,而不是对这些元素的属性的引用。对不起@ScottMarcus,但是你错了。在我的示例中的view\u email
函数中有一个fetchfetch(`/emails/${emailId}```)。然后(response=>response.json())。然后(email=>{…}
解析为/emails/${emailId}
的响应,并返回一个名为emai>的对象