【问题标题】:AddEventListener to multiple elements and return their values - How?AddEventListener 到多个元素并返回它们的值 - 如何?
【发布时间】:2021-11-04 20:03:51
【问题描述】:

我有一个类别列表:

<ul id="categories">
    <li>aaa</li>
    <li>bbb</li>
    <li>ccc</li>
</ul>

我想返回类别 onClick 的值。 因此,我尝试将它们全部选中,为它们中的每一个创建一个addEventListener。但我不知道如何才能将cat.textContent 的值获取到回调范围之外或函数本身...

async getCategoryNameOnClick() {
    var cats = document.querySelectorAll('#categories li')
    cats.forEach( (cat) => {
        cat.addEventListener('click', () => {
            console.log(cat.textContent)
        })
    })
}

我尝试用一​​个承诺来解决,但是在解决之后它就不再起作用了。既不使用var

【问题讨论】:

  • 由于多种原因无法返回该值:事件发生在未来的某个时间点,而不是在调用函数时。该事件将发生多次,但一个函数只能返回一次。您可以使用 Promise 解决第一个问题,但即使是 Promise 也只能解决一次,因此它不会获得未来的点击次数。那么您究竟想如何处理点击事件呢?最简单的解决方案是传递回调并让事件处理程序调用回调。或者,您可以使用 rxjs.dev 之类的东西作为更高级别的抽象。

标签: javascript ecmascript-6 callback closures addeventlistener


【解决方案1】:

检查捕获所选 li 文本的按钮单击逻辑。希望这能回答您的问题。

var categoresBtn = document.querySelector("button");
var dropdownOptionsContainer = document.querySelector(".options-container");
var categoriesOption = document.querySelectorAll(".option a");

categoresBtn.addEventListener("click", function(e) {
  e.preventDefault()
  dropdownOptionsContainer.classList.toggle("open")
});

//logic to catch the clicked li tag
var clickFn = function(e) {
  console.log("Selected <li>: ", e.target.innerText);
  e.preventDefault()
  dropdownOptionsContainer.classList.remove("open");
  categoresBtn.innerHTML = this.text;
  var activeLink = document.querySelector(".option .active");

  if (activeLink) {
    activeLink.classList.remove("active");
  }
  this.classList.add("active");
}

for (var i = 0; i < categoriesOption.length; i++) {
  categoriesOption[i].addEventListener("mousedown", clickFn, false);
}
.dropdown-container {
  max-width: 500px;
  margin-top: 10px;
  margin-left: 0px;
}

.dropdown-container button {
  position: relative;
  background: none;
  border: none;
  outline: none;
  font-size: 16px;
  border-bottom: 2px solid #9b9b9b;
  padding-bottom: 8px;
  min-width: 150px;
  text-align: left;
  outline: none;
  cursor: pointer;
  z-index: 2;
}

.dropdown-container button:after {
  content: '▾';
  position: absolute;
  right: 0px;
  top: 0%;
  color: rgb(142, 142, 142);
}

.dropdown-container .dropdown-wrap {
  position: relative;
}

.dropdown-container .dropdown-wrap .options-container {
  list-style: none;
  margin: 0;
  padding: 0;
  background: white;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.24);
  display: inline-block;
  position: absolute;
  left: 0;
  bottom: 0;
  opacity: 0;
  -webkit-transform: scale(0.8) translate3d(-20px, 0px, 0);
  transform: scale(0.8) translate3d(-20px, 0px, 0);
  -webkit-transition: opacity 0.1s cubic-bezier(0.5, 2, 0.5, 0.75), -webkit-transform 0.3s cubic-bezier(0.5, 2, 0.5, 0.75);
  transition: opacity 0.1s cubic-bezier(0.5, 2, 0.5, 0.75), -webkit-transform 0.3s cubic-bezier(0.5, 2, 0.5, 0.75);
  transition: opacity 0.1s cubic-bezier(0.5, 2, 0.5, 0.75), transform 0.3s cubic-bezier(0.5, 2, 0.5, 0.75);
  transition: opacity 0.1s cubic-bezier(0.5, 2, 0.5, 0.75), transform 0.3s cubic-bezier(0.5, 2, 0.5, 0.75), -webkit-transform 0.3s cubic-bezier(0.5, 2, 0.5, 0.75);
  -webkit-transform-origin: 0 100%;
  transform-origin: 0 100%;
  z-index: 1;
}

.dropdown-container .dropdown-wrap .options-container.open {
  opacity: 1;
  -webkit-transform: scale(1) translate3d(0, 0, 0);
  transform: scale(1) translate3d(0, 0, 0);
  z-index: 5;
}

.dropdown-container .dropdown-wrap .options-container li {
  display: inline-block;
}

.dropdown-container .dropdown-wrap .options-container li a {
  text-decoration: none;
  display: inline-block;
  padding: 10px 16px;
  color: #2975DA;
}

.dropdown-container .dropdown-wrap .options-container li a:hover {
  color: #2269c7;
}

.dropdown-container .dropdown-wrap .options-container li a.active {
  border-bottom: 2px solid #9b9b9b;
  color: #9b9b9b;
}

.dropdown-container .dropdown-wrap .options-container li a.active:hover {
  color: #9b9b9b;
}
<div class="dropdown-container">
  <div class="dropdown-wrap">
    <button>Categories</button>
    <ul id="categoriesDDl" class="options-container">
      <li class="option">
        <a href="#">aaa</a>
      </li>
      <li class="option">
        <a href="#">bbb</a>
      </li>
      <li class="option">
        <a href="#">ccc</a>
      </li>
    </ul>
  </div>
</div>

【讨论】:

  • Uhmm .. 这个答案添加了不必要的 CSS 和 HTML 标记。不过,这是一个非常有创意的答案。但是忽略这一切,基本上你所做的就是使用回调函数,并获取innerText。因此,您能够在回调中检索单击元素的值(与我所做的相同),但不能从回调中提取它以供在其他任何地方进一步使用。这就是我所要求的。我认为在这种情况下是否使用e.preventDefault() 并没有什么不同。
【解决方案2】:

好吧,首先,你把它放在一个不被调用的函数中,并使它成为一个不需要的异步函数,附议你没有锚或按钮标签就不能点击列表。所以这就是我想出来的,它可以满足你的要求。

    <ul id="categories" >
  <li><button>aaa</button></li>
    <li><button>bbb</button></li>
    <li><button>ccc</button></li>
</ul>

let cats = document.querySelectorAll('#categories li');

cats.forEach( (cat) => {
       cat.addEventListener('click', () => {
             console.log(cat.textContent)
         })
});

我把它们放在按钮中,但你也可以使用锚标签。

【讨论】:

  • “如果没有锚点或按钮标签,您无法使列表点击” 虽然使用按钮或链接很好,但这不是必需的。点击事件也会在其他元素上触发。
  • 据我所知 buttona 元素不需要向 DOM 中的元素添加事件侦听器。您的回复没有回答如何在回调之外获取cat.textContent。并且不能解决多次单击它并保持它返回和工作的问题。该函数没有被调用,因为它是整个类的摘录。但这是说明问题所需的唯一部分。
猜你喜欢
  • 2017-12-01
  • 1970-01-01
  • 1970-01-01
  • 2012-02-16
  • 2017-12-08
  • 1970-01-01
  • 1970-01-01
  • 2015-08-21
  • 2021-09-08
相关资源
最近更新 更多