【问题标题】:Create Eventlisteners for detailstag dynamically?动态为详细信息标签创建事件侦听器?
【发布时间】:2022-01-25 05:30:09
【问题描述】:

为什么会这样:

const details = document.querySelector('details')

document.getElementById("details1").addEventListener("toggle", event => {
  if (details1.open) {
    changeText1("open");
  } else {
    changeText1("closed");
  }
});

document.getElementById("details2").addEventListener("toggle", event => {
  if (details2.open) {
    changeText2("open");
  } else {
    changeText2("closed");
  };
});


function changeText1(status) {
 if(status == "open") {
    document.getElementById("p1").innerText = "opened";
    } else if (status == "closed") {
    document.getElementById("p1").innerText = "closed";
    }
} 

function changeText2(status) {
 if(status == "open") {
    document.getElementById("p2").innerText = "opened";
    } else if (status == "closed") {
    document.getElementById("p2").innerText = "closed";
    }
}
<html>
<body>
<details id="details1">
  <summary>#1</summary>text
</details>
<details id="details2">
  <summary>#2</summary>text
</details>

<p id="p1">not opened or closed</p>
<p id="p2">not opened or closed</p>

</body>
</html>

这是行不通的吗:

const details = document.querySelector('details')

function changeText(detailnr, status) {
 let pnr = "p" + detailnr; 
 if(status == "open") {
    document.getElementById(pnr).innerText = "opened";
    } else {
    document.getElementById(pnr).innerText = "closed";
    }
}

function maaklistner(detailsnr){
 let detailsid = "details" + detailsnr; 
 document.getElementById(detailsid).addEventListener("toggle", event => {
  if (detailsid.open) {
    changeText(detailsnr, "open");
  } else {
    changeText(detailsnr, "closed");
  } 
});
}


for(let i = 1; i < 3; i++){
 maaklistner(i); 
}
<html>
<body>
<details id="details1">
  <summary>#1</summary>text
</details>
<details id="details2">
  <summary>#2</summary>text
</details>

<p id="p1">not opened or closed</p>
<p id="p2">not opened or closed</p>

</body>
</html>

虽然代码本质上完全是重复的......

似乎事件侦听器本身已创建。但是,在 seconde 代码中没有正确处理 details.opened 语句,而在第一个代码中确实可以使用相同的方法。

有没有办法让第二种方法起作用?因为我需要创建超过 2000 个...

【问题讨论】:

    标签: javascript html details-tag


    【解决方案1】:

    它不起作用,因为您使用detailsid 检查details 元素是否打开。您需要使用包含 id detailsid 的元素。

    只需将detailsid.open 替换为document.getElementById(detailsid).open

    这是一个有效的例子:

    const details = document.querySelector('details')
    
    function changeText(detailnr, status) {
      let pnr = "p" + detailnr;
      if (status == "open") {
        document.getElementById(pnr).innerText = "opened";
      } else {
        document.getElementById(pnr).innerText = "closed";
      }
    }
    
    function maaklistner(detailsnr) {
      let detailsid = "details" + detailsnr;
      
      document.getElementById(detailsid).addEventListener("toggle", event => {
        if (document.getElementById(detailsid).open) {
          changeText(detailsnr, "open");
        } else {
          changeText(detailsnr, "closed");
        }
      });
    }
    
    
    for (let i = 1; i < 3; i++) {
      maaklistner(i);
    }
    <details id="details1">
      <summary>#1</summary>text
    </details>
    <details id="details2">
      <summary>#2</summary>text
    </details>
    
    <p id="p1">not opened or closed</p>
    <p id="p2">not opened or closed</p>

    【讨论】:

    • 啊,比我快,恭喜老哥
    【解决方案2】:

    添加document.getElementById(detailsid) 代替detailsid

    const details = document.querySelector('details')
    
    function changeText(detailnr, status) {
      let pnr = "p" + detailnr;
      if (status == "open") {
        document.getElementById(pnr).innerText = "opened";
      } else {
        document.getElementById(pnr).innerText = "closed";
      }
    }
    
    function maaklistner(detailsnr) {
      let detailsid = "details" + detailsnr;
      
      document.getElementById(detailsid).addEventListener("toggle", event => {
        if (document.getElementById(detailsid).open) {
          changeText(detailsnr, "open");
        } else {
          changeText(detailsnr, "closed");
        }
      });
    }
    
    
    for (let i = 1; i < 3; i++) {
      maaklistner(i);
    }
    <details id="details1">
      <summary>#1</summary>text
    </details>
    <details id="details2">
      <summary>#2</summary>text
    </details>
    
    <p id="p1">not opened or closed</p>
    <p id="p2">not opened or closed</p>

    【讨论】:

      【解决方案3】:

      我建议您在这里忘记唯一 ID...您可以使用 forEach 循环为每个 details 元素设置一个事件侦听器。

      data-* 属性将保存 p 的索引(从零开始)以作为文本更改的目标。

      看看吧!它更简单。

      // Get all the details elements
      let details = document.querySelectorAll("details");
      
      // Get an array from all the p elements
      let stateIndicators = Array.from(document.querySelectorAll(".stateWrapper p"))
      
      // For each details element, set an event listener
      details.forEach(function(detail) {
        detail.addEventListener("toggle", function(e) {
        
          // Get its index from the data attribute
          let index = this.dataset.index
          
          // Change the text based on the open state
          stateIndicators[index].innerText = this.open ? "opened" : "closed"
        })
      })
      <html>
      
      <body>
        <details data-index="0">
          <summary>#1</summary>text
        </details>
        <details data-index="1">
          <summary>#2</summary>text
        </details>
        <details data-index="2">
          <summary>#3</summary>text
        </details>
        <details data-index="3">
          <summary>#4</summary>text
        </details>
        <details data-index="4">
          <summary>#5</summary>text
        </details>
      
        <div class="stateWrapper"><!-- usefull wrapper here -->
          <p>not opened or closed</p>
          <p>not opened or closed</p>
          <p>not opened or closed</p>
          <p>not opened or closed</p>
          <p>not opened or closed</p>
        </div>
      
      </body>
      
      </html>

      【讨论】:

      • 谢谢,我不怀疑这是一种更聪明的方法,唯一的问题是,我刚接触 javascript 几天,而我需要应用它的实际代码更复杂。每个细节都包含一个表格和值(图片),这是通过组合其他单元格确定的(仅在打开细节时,以防止大量加载)。那么,例如,当每个摘要之后的“文本”-文本 :-) 不同时,您将如何编写它,而不是显示“已打开”,而是显示“nr + 文本”?我无法按照您的方式(必须是我)完成,“不太优雅的方式”现在正在发挥作用。
      【解决方案4】:

      使用“点击”事件,因为“切换”不会冒泡。使用 Event Delegation 需要事件冒泡,它允许您添加单个事件处理程序来侦听无限量标签的事件,包括动态添加的标签。

      const flipDetails = event => {
        const parent = event.currentTarget;
        const clicked = event.target;
        const nodes = [...parent.children];
        const log = document.querySelector('output');
        if (clicked !== parent && clicked.matches('summary')) {
          let dtl = clicked.parentElement;
          let pos = nodes.indexOf(dtl)+1;
          let status = dtl.open === true ? `${pos}: Closed` : `${pos}: Open`;
          log.innerHTML += '<br>'+ status;
        }
      }
      
      const main = document.querySelector('main');
      
      main.addEventListener("click", flipDetails);
      
      // For demo only
      document.querySelector('output').insertAdjacentHTML('beforeBegin', `
          <details>
            <summary>Added Dynamically</summary>text
          </details>`);
      output::before {content: 'Status: '}
      <html>
      
      <body>
        <main>
          <details>
            <summary>#1</summary>text
          </details>
          <details>
            <summary>#2</summary>text
          </details>
          <output></output>
        </main>
      </body>
      
      </html>

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2015-10-31
        • 1970-01-01
        • 2020-12-05
        • 2019-05-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多