css 为什么我不能用parentNode和nextSibling调用正确的div?

bwleehnv  于 2023-01-22  发布在  其他
关注(0)|答案(3)|浏览(149)

这是我的代码:

const copyContent = async() => {
  try {
    let copyText = event.target.parentNode.lastChild.value;
    let copied = event.target.nextSibling.nextSibling;

    await navigator.clipboard.writeText(copyText);
    console.log('Content copied to clipboard');
    copied.style.animation = "appear 4s linear";
  } catch (err) {
    console.error('Failed to copy: ', err);
  }
}
<div class="cards-container">
  <div class="card">
    <div class="card-container" onclick="copyContent()">
      <div>
        <img src="https://google.com">
        <span>#1</span>
      </div>
      <div class="copied">
        <span>Copied!</span>
      </div>
    </div>
    <input class="link" type="text" value="https://google.com">
  </div>

  <div class="card">
    <div class="card-container" onclick="copyContent()">
      <div>
        <img src="https://yahoo.com">
        <span>#2</span>
      </div>
      <div class="copied">
        <span>Copied!</span>
      </div>
    </div>
    <input class="link" type="text" value="https://yahoo.com">
  </div>
</div>

这是我得到的错误:
复制失败:TypeError:无法读取copyContent处的null属性(阅读“style”)
我知道我错在哪里了:

let copyText = event.target.parentNode.lastChild.value;

let copied = event.target.nextSibling.nextSibling;

但是我试过很多不同的组合,都不起作用。我避免使用身份证,因为我会有很多“卡”。

7hiiyaii

7hiiyaii1#

需要解决的问题:

  • 不建议使用全局event窗口属性,尤其是在async函数中,该函数可能会读取事件对象以获取在调用该函数后发生的事件。
  • 如果在HTML onEventName属性中添加了事件处理程序,请将event作为参数传递给调用的函数。(如果您想知道,"event"将作为参数传递给HTML解析器根据属性的文本值生成的函数。)
  • 最好使用element.addEventListener语法在JavaScript中添加事件处理程序。
  • 单击事件目标是鼠标单击时位于鼠标下方的元素。在本例中,它可能是.card-container分区中不同嵌套级别的各种子元素之一。虽然您 * 可以 * 使用closest来查找分区,但它已经作为event.currentTarget可用,因为这是处理事件的位置。
  • 元素(getter)属性nextSiblingpreviousSibingfirstChildlastChild非常能够返回文本和HTML注解节点-这不是您在本例中想要的。在查找元素时,请使用nextElementSiblingpreviousElementSiblingfirstElementChildlastElementChild版本。

这里是一个修改过的例子,使用了一个过渡而不是动画,因为它没有包含在帖子中。复制到剪贴板的值是卡片容器后面的input元素的文本内容-如果应该复制其他内容,请修改。

"use strict";
const copyContent = async(event) => {  // takes event object argument
  try {
    let currentTarget = event.currentTarget; // should be div.card-container 
    const input = currentTarget.parentNode.lastElementChild;
    const copyText =input.value;

      console.log("currentTarget = %s.%s", currentTarget.tagName, currentTarget.className); // debug
      console.log("input: ", input)
      console.log( "copyText:", copyText);
    let copied = currentTarget.firstElementChild.nextElementSibling;
    await navigator.clipboard.writeText(copyText);
      console.log('Content copied to clipboard');
    copied.style.color = "forestgreen"; // simplified
  } catch (err) {
    console.error('Failed to copy: ', err);
  }
}
.card-container {
  border: thin solid green;
  background-color: honeydew;
}
.copied { 
  color: white;
  transition: color 3s;
}
<div class="cards-container">
    <div class="card">
        <div class="card-container" onclick="copyContent(event)">
            <div>
                <img src="http://example.com">
                <span>#1</span>
            </div>
           <div class="copied">
               <span>copied to clipboard</span>
           </div>
        </div>
       <input class="link" type="text" value="http://example.com">
  </div>

  <div class="card">
    <div class="card-container" onclick="copyContent(event)">
      <div>
        <img src="https://yahoo.com">
        <span>#2</span>
      </div>
      <div class="copied">
        <span>copied to clipboard</span>
      </div>
    </div>
    <input class="link" type="text" value="http://example.com">
  </div>
</div>
eqqqjvef

eqqqjvef2#

首先,您没有在onclick上传递事件,它应该是onclick="copyContent(event)"
第二,正如一些评论所提到的,event.target可能不是你所想的元素,onclick被附加到card-container div和它的所有子元素上,所以如果你点击带有文本Copied!的span,目标的图像或其他东西就会改变。
可以使用closest方法来解决这个问题

const copyContent = async(event) => {
  try {
    //if parent node its the actual target, use actual target as parent node, instead search for the closest element that has card-container class
    let parentNode = event.target.classList.contains("card-container") ? event.target : event.target.closest(".card-container")
    //from the parent node, search for the input
    let copyText = parentNode.querySelector("input.link");
    //from the parent node, search the copied span element?
    let copied = parentNode.querySelector(".copied span)";

    await navigator.clipboard.writeText(copyText);
    console.log('Content copied to clipboard');
    copied.style.animation = "appear 4s linear";
  } catch (err) {
    console.error('Failed to copy: ', err);
  }
}

观察结果:我认为使函数异步应该是不必要的,因为也等待导航器

inn6fuwd

inn6fuwd3#

您收到的错误消息指出event.targetnull,这意味着事件对象没有被传递给copyContent函数。解决这个问题的一个方法是将事件对象作为参数传递给函数。

<div class="card-container" onclick="copyContent(event)">

然后,在函数中,您可以引用作为参数const copyContent = async(event) => {...传递的事件。此外,您可以考虑在函数中使用event.currentTarget而不是event.target,因为差异:target是触发事件的元素(例如,用户点击),currentTarget是事件侦听器附加到的元素。另一个想法是使用querySelector来选择元素。

let copyText = event.currentTarget.parentNode.querySelector('.link').value;
let copied = event.currentTarget.querySelector('.copied'); //Not sure if this is what you want

您可以使用这个querySelector方法来选择元素,因此不必使用parentNodenextSibling

相关问题