在循环中应用addEventListener

时间:2017-03-14 17:08:33

标签: javascript loops addeventlistener

这是我的第一个问题因此我提前道歉可能会使用错误的网络礼节。

我正在探索使用Javascript实现双向绑定的不同解决方案,我遇到了常见错误'当在for循环中使用Closure因此总是在最后一个项目上设置计数器变量时,我在这个网站上找到了解释(和解决方案),但后来我遇到了一个不同的问题我很感激一些帮助

想象一下,我们有两组数据,其中一组包含适当的数据,即:

   var data = {
      data1 : 0
   };

另一个描述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'
      }
    }

  }

请参阅下面的完整代码段



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>
&#13;
&#13;
&#13;

现在,如果我们点击按钮[1],它将更新自己和以下内容,从而产生以下序列:

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

我们刷新页面,这次点击按钮[2],顺序为:

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

按钮[3]而是仅更新自己

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

我在发布之前确实查找了这个主题,但我发现的所有问题都与此类似:addEventListener using for loop and passing values,其中问题是计数器变量始终保持最后一个值

在这种情况下,似乎问题恰恰相反,或者保持初始值的对象和随后的对象(如果你一直点击就会看到我的意思)

我做错了什么?

1 个答案:

答案 0 :(得分:0)

问题似乎是你要在每个&#34;刷新&#34;上重新附加你的子元素,这会改变元素的顺序,并给出刷新多个元素的错觉。

您需要区分初始渲染和后续刷新。

我建议您从渲染功能中删除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);
}

请注意,有多个&#34;问题&#34;使用您的代码,包括多个位置的全局变量。而且我不相信您的架构会很好地扩展。但是,这些问题超出了你的问题的范围,你会随时学习......没有理由期望每个人都知道一切,你可能会发现你当前的解决方案适合你需要的东西它要做。

&#13;
&#13;
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);
      }
&#13;
div {
  padding: 10px;
  border: solid 1px black;
  margin: 5px;
  display: inline-block;
}
&#13;
<html>

<head>
</head>

<body>
  <div id="main"></div>
</body>

</html>
&#13;
&#13;
&#13;