Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/388.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 难以将唯一事件侦听器添加到已创建的<;部门>;通过for循环的元素_Javascript_Html - Fatal编程技术网

Javascript 难以将唯一事件侦听器添加到已创建的<;部门>;通过for循环的元素

Javascript 难以将唯一事件侦听器添加到已创建的<;部门>;通过for循环的元素,javascript,html,Javascript,Html,我正在进行一个学习JavaScript的项目,目标是在一个单页web应用程序中动态地提供电子邮件。应用程序的HTML是使用createElement JS方法创建的。到目前为止,我已成功显示“收件箱”页面,其中包含所有电子邮件,如下图所示: 我目前正试图通过使用addEventListener使这些单独的电子邮件都可以点击。我遇到的问题是,每当我单击任何电子邮件时,收件箱中的第一封电子邮件(id:1,主题:测试电子邮件)都会被呈现出来,并且无法查看任何其他电子邮件 我可以看到,对于所有创建的

我正在进行一个学习JavaScript的项目,目标是在一个单页web应用程序中动态地提供电子邮件。应用程序的HTML是使用createElement JS方法创建的。到目前为止,我已成功显示“收件箱”页面,其中包含所有电子邮件,如下图所示:

我目前正试图通过使用addEventListener使这些单独的电子邮件都可以点击。我遇到的问题是,每当我单击任何电子邮件时,收件箱中的第一封电子邮件(id:1,主题:测试电子邮件)都会被呈现出来,并且无法查看任何其他电子邮件

我可以看到,对于所有创建的div,都将相同的email.id应用于事件侦听器,尽管所有div都已正确创建,所有信息都来自相应的电子邮件

下面是load mailbox JS,它呈现收件箱中的所有电子邮件:

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
与param
email
没有任何问题,因为函数本身会新获取电子邮件,然后在
中获取
email
(email=>
fetch
的JSON,你对
email.id
的看法是正确的(我没有看到问题中的JSON),但是
查看\u email
并没有获取
email
。它使用
email
来获取
id
。而且,在您的建议中,您甚至没有
email
可供使用。不管怎样,我的原始观点仍然是,最好传递对DOM元素的引用,而不是对这些元素的属性的引用。对不起@ScottMarcus,但是你错了。在我的示例中的
view\u email
函数中有一个fetch
fetch(`/emails/${emailId}```)。然后(response=>response.json())。然后(email=>{…}
解析为
/emails/${emailId}
的响应,并返回一个名为
emai>的对象