将列表项元素的数组推送到循环外的数组(纯JavaScript)

时间:2016-10-22 12:16:15

标签: javascript arrays

我正在尝试将收集的项目(水果)列表推送到循环外的空数组中。

然后我想使用addEventListener从数组中访问每个水果,并在点击时将它们附加到容器(水果篮)。

我让函数本身以不同的方式正常工作:https://jsfiddle.net/ec4hqas2/

然而,这是循环中的eventListener 我希望它在外面,如下所示:

https://jsfiddle.net/ec4hqas2/8/

(function() {

  var fruits = document.querySelectorAll('.list li');
  var fruit_basket = document.querySelector('.fruit-basket');
  var fruits_array = [];

  for (var i = 0; i < fruits.length; i++) {
    // Returns only numbers
    fruits_array.push(i);

    /* This returns the entire NodeList:
    fruits_array.push(fruits[i]); 
    */
  }
  console.log(fruits_array); // result: [0,1,2]

  // Append each clicked fruit to fruit basket
  fruits_array[i].addEventListener('click', function() {
    fruit_basket.appendChild(this);

  });

})();

问题是我只能设法将水果的数量从循环推送到数组。如何将带有水果名称的整个列表项元素推送到空数组?

我试图这样做的原因,是我记得被告知将eventListener保持在循环之外是一个很好的做法,但我可能会混淆一些,这是一个坏主意首先是什么?

我阅读这些文章试图围绕NodeLists&amp;数组,但我仍然感到困惑: https://davidwalsh.name/nodelist-array https://toddmotto.com/a-comprehensive-dive-into-nodelists-arrays-converting-nodelists-and-understanding-the-dom/

任何帮助非常感谢! : - )

3 个答案:

答案 0 :(得分:2)

在循环内部或外部添加事件监听器并不重要的问题是在循环中多次创建函数,就像使用匿名函数一样:

for (var i = 0; i < fruits.length; i++) {
  var fruit = fruits[i];
  fruit.addEventListener('click', function() {
    fruit_basket.appendChild(this)
  });
}

&#39;更好&#39;避免在每个循环上重新创建匿名函数的方法是使用命名函数并将该函数指定为循环中的事件处理程序:

// declaring the variables using let,
// first we retrieve all of the <li> elements held
// inside of an ancestor element with the class of
// 'list':
let fruits = document.querySelectorAll('.list li'),

// retrieving only the first - if any - element with
// the class of 'fruit-basket':
  fruit_basket = document.querySelector('.fruit-basket');

// creating a named-function, to avoid re-recreating
// an anonymous function, which will be bound as the
// event-handler later:
function addToBasket(event) {
  // the 'event' object, as well as the 'this'
  // is passed automatically from the
  // EventTarget.addEventListener() method,
  // the event.target is the element upon
  // which the listened-for event was first
  // triggered (here the <li> or a descendant
  // of that <li>):
  fruit_basket.appendChild(event.target);
}

for (let i = 0; i < fruits.length; i++) {

  // iterating through the NodeList returned
  // by document.querySelectorAll() and binding
  // the addToBasket function as the event-handler
  // for the 'click' event:
  fruits[i].addEventListener('click', addToBasket);
}

&#13;
&#13;
let fruits = document.querySelectorAll('.list li'),
  fruit_basket = document.querySelector('.fruit-basket');

function addToBasket(event) {
  fruit_basket.appendChild(event.target);
}

for (let i = 0; i < fruits.length; i++) {
  fruits[i].addEventListener('click', addToBasket);
}
&#13;
ul {
  border: 1px solid #f90;
  width: 80%;
  margin: 0 auto 1em auto;
  border-radius: 0.5em;
  min-height: 6em;
  line-height: 2em;
}
&#13;
<ul class="list">
  <li>Apple</li>
  <li>Banana</li>
  <li>Orange</li>
</ul>

<ul class="fruit-basket">

</ul>
&#13;
&#13;
&#13;

JS Fiddle demo

顺便提一下,有一种替代方法,使用<ul>元素:

// again, creating a named-function to act as the
// event-handler:
function addToBasket(event) {
  // finding the relevant element to which
  // the event.target should be appended as
  // a child, and appending the event.target:
  document.querySelector('.fruit-basket').appendChild(event.target);
}

// here we create an Array from the Array-like
// NodeList returned by document.querySelectorAll:    
Array.from(
  document.querySelectorAll('ul')

// iterating over that Array of nodes:
).forEach(

  // we use an Arrow function to bind the addToBasket
  // function as the event-handler for the 'click'
  // event on each of the <ul> elements:
  list => list.addEventListener('click', addToBasket)
);

&#13;
&#13;
let fruits = document.querySelectorAll('.list li'),
  fruit_basket = document.querySelector('.fruit-basket');

function addToBasket(event) {
  document.querySelector('.fruit-basket').appendChild(event.target);
}

Array.from(
  document.querySelectorAll('ul')
).forEach(
  list => list.addEventListener('click', addToBasket)
);
&#13;
ul {
  border: 1px solid #f90;
  width: 80%;
  margin: 0 auto 1em auto;
  border-radius: 0.5em;
  min-height: 6em;
  line-height: 2em;
}
&#13;
<ul class="list">
  <li>Apple</li>
  <li>Banana</li>
  <li>Orange</li>
</ul>

<ul class="fruit-basket">

</ul>
&#13;
&#13;
&#13;

JS Fiddle demo

参考文献:

答案 1 :(得分:2)

您甚至不需要for循环。

向容器添加事件侦听器,并将e.target追加到fruit-basket

var fruits = document.querySelectorAll('.list');
var fruit_basket = document.querySelector('.fruit-basket');

fruits[0].addEventListener('click', function(e) {
    if(e.target.tagName === 'LI')
      fruit_basket.appendChild(e.target)    
});

工作小提琴:https://jsfiddle.net/h0zmkyyn/

答案 2 :(得分:1)

你被告知错了,你必须单独为每个元素添加事件监听器,所以你必须使用一个循环。

元素集合已经是类似于数组的nodeList,因此不需要额外的数组。

你可以做的是定义循环外的回调,因此没有为每次迭代定义函数,但对于少数几个元素来说它并不重要

(function() {

    var fruits       = document.querySelectorAll('.list li');
    var fruit_basket = document.querySelector('.fruit-basket');
    var cb_func      = function() {
        fruit_basket.appendChild(this);
    };

    for (var i = 0; i < fruits.length; i++) {
        fruits[i].addEventListener('click', cb_func);
    }

})();