简体   繁体   English

在循环中应用addEventListener

[英]Applying an addEventListener in a loop

This is my first question ever thus I apologize in advance might I use the wrong netiquette. 这是我的第一个问题,因此如果您使用错误的网络礼节,我要向您道歉。

I'm exploring different solutions to implement a two way binding using Javascript only, I ran across the 'common mistake' when using a Closure inside a for loop hence having the counter variable always set on the last item, I found the explanation (and the solution) on this very site but then I came across a different issue I'd appreciate some help for. 我正在探索不同的解决方案以仅使用Javascript实现双向绑定,当在for循环中使用闭包时遇到了“常见错误”,因此总是在最后一项设置计数器变量,我找到了解释(和解决方案)在这个网站上,但后来我遇到了一个不同的问题,希望对您有所帮助。

Imagine we have two sets of data, where one contains proper data, ie: 假设我们有两组数据,其中一组包含适当的数据,即:

   var data = {
      data1 : 0
   };

The other a collection of objects describing 3 elements : 另一个是描述3个元素的对象的集合:

  var elements = {

    1 : {
      target  : 'main',
      value   : data,
      element : 'div',
      events  : {
        click : 'add'
      }
    },

    2 : {
      target  : 'main',
      value   : data,
      element : 'div',
      events  : {
        click : 'add'
      }
    },

    3 : {
      target  : 'main',
      value   : data,
      element : 'div',
      events  : {
        click : 'add'
      }
    }

  }

See the complete codesnippet below 请参阅下面的完整代码段

 var data = { data1 : 0 }; var elements = { 1 : { target : 'main', value : data, element : 'div', events : { click : 'add' } }, 2 : { target : 'main', value : data, element : 'div', events : { click : 'add' } }, 3 : { target : 'main', value : data, element : 'div', events : { click : 'add' } } } // This is our main object, we define the properties only ... var _elem = function (props,id){ this.id = id; this.target = document.getElementById(props.target); this.element = document.createElement(props.element); this.events = props.events; this.value = props.value; } // Then we add a method to render it on the page ... _elem.prototype.render = function(){ // I added the Object Id for debugging purposes this.element.innerHTML = this.value.data1 + ' ['+this.id+']'; this.target.appendChild(this.element); } // ... and another to change the underlying data and re - render it _elem.prototype.add = function(){ // Since the data is a reference to the same data object // We expect to change the value for all the elements this.value.data1++; this.render(); } // First we looop trough the array with the element definition and // Cast each item into a new element for(var el in elements){ elements[el] = new _elem(elements[el],el); } // Then we apply the event listener (if any event description is present) for(var el in elements){ if(!elements[el].hasOwnProperty( 'events' )){ continue; } // We use the anonymous function here to avoid the "common mistake" (function() { var obj = elements[el]; var events = obj.events; for(var ev in events){ obj.element.addEventListener(ev,function(){ obj[events[ev]]() }); } })(); } // And finally we render all the elements on the page for(var el in elements){ elements[el].render(elements[el]); } 
 div { padding: 10px; border: solid 1px black; margin: 5px; display: inline-block; } 
 <html> <head> </head> <body> <div id="main"></div> </body> </html> 

Now, if we click button [1] it will update itself and the following, resulting in this sequence: 现在,如果我们单击按钮[1],它将进行自我更新并更新以下内容,从而导致此顺序:

0 [2] 0 [3] 1 [1] 0 [2] 0 [3] 1 [1]

We refresh the page and this time click button [2], the sequence will be: 我们刷新页面,这次单击按钮[2],顺序为:

0 [1] 0 [3] 1 [2] 0 [1] 0 [3] 1 [2]

Button [3] Instead will update itself only 按钮[3]只会更新自身

0 [1] 0 [2] 1 [3] 0 [1] 0 [2] 1 [3]

I did look for this topic before posting but all I could find were questions similar to this: addEventListener using for loop and passing values , where the issue was the counter variable holding always the last value 我确实在发布之前寻找了这个主题,但是我发现的所有问题都与此类似: addEventListener使用for循环并传递值 ,其中问题是计数器变量始终保持最后一个值

In this case instead it seems the issue to be the opposite, or the object holding the initial value and the ones following (if you keep clicking you will see what I mean) 在这种情况下,问题似乎恰恰相反,或者是持有初始值和其后一个值的对象(如果继续单击,您将明白我的意思)。

What am I do wrong? 我做错了什么?

The issue appears to be that you are re-appending your child elements on each "refresh", which shifts the order of the elements and gives the illusion of refreshing multiple elements. 问题似乎是您在每个“刷新”上重新添加了子元素,这改变了元素的顺序并给人一种刷新多个元素的幻觉。

You need to differentiate between an initial render and subsequent refreshes. 您需要区分初始渲染和后续刷新。

I recommend that you remove the append from your render function and instead handle appending in your final for loop: 我建议您从渲染函数中删除append ,而应在最终的for循环中处理附加:

// And finally we render all the elements on the page  
for(el in elements){
  elements[el].render(elements[el]);
  elements[el].target.append(elements[el].element);
}

Note that there are multiple "issues" with your code, including global variables in several locations. 请注意,您的代码有多个“问题”,包括多个位置的全局变量。 And I'm not confident that your architecture will scale well. 而且我不确定您的体系结构能否很好地扩展。 But, those issues are outside the scope of your question, and you'll learn as you go... no reason to expect that everyone will know everything, and you may find that your current solution works just fine for what you need it to do. 但是,这些问题不在您的问题范围内,您将继续学习...没有理由期望每个人都知道所有事情,并且您可能会发现当前的解决方案可以很好地满足您的需求做。

 var data = { data1 : 0 }; var elements = { 1 : { target : 'main', value : data, element : 'div', events : { click : 'add' } }, 2 : { target : 'main', value : data, element : 'div', events : { click : 'add' } }, 3 : { target : 'main', value : data, element : 'div', events : { click : 'add' } } } // This is our main object, we define the properties only ... var _elem = function (props,id){ this.id = id; this.target = document.getElementById(props.target); this.element = document.createElement(props.element); this.events = props.events; this.value = props.value; } // Then we add a method to render it on the page ... _elem.prototype.render = function(){ // I added the Object Id for debugging purposes this.element.innerHTML = this.value.data1 + ' ['+this.id+']'; } // ... and another to change the underlying data and re - render it _elem.prototype.add = function(){ // Since the data is a reference to the same data object // We expect to change the value for all the elements this.value.data1++; this.render(); } // First we looop trough the array with the element definition and // Cast each item into a new element for(var el in elements){ elements[el] = new _elem(elements[el],el); } // Then we apply the event listener (if any event description is present) for(var el in elements){ if(!elements[el].hasOwnProperty( 'events' )){ continue; } // We use the anonymous function here to avoid the "common mistake" (function() { var obj = elements[el]; var events = obj.events; for(ev in events){ obj.element.addEventListener(ev,function(){ obj[events[ev]]() }); } })(); } // And finally we render all the elements on the page for(var el in elements){ elements[el].render(elements[el]); elements[el].target.appendChild(elements[el].element); } 
 div { padding: 10px; border: solid 1px black; margin: 5px; display: inline-block; } 
 <html> <head> </head> <body> <div id="main"></div> </body> </html> 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM