【问题标题】:Get checked checkboxes from most recent .change() event从最近的 .change() 事件中获取选中的复选框
【发布时间】:2017-08-22 21:28:16
【问题描述】:

我在解决一个基本问题时遇到了麻烦,但我什至无法弄清楚帮助自己研究的合适术语是什么。

本质上,我有一个.change() 侦听器,用于侦听div 中复选框的变化(它们切换传单地图层)。我想创建一个变量来保存选中复选框的列表。我可以这样做,但是,对于.change() 侦听器触发的每次时间,它似乎都会保留检查了哪些层的各个实例。一些应该重新创建问题的代码:

var lyrs;

$("div#myID input:checkbox").change(function() {
    lyrs = $("div#myID input[type='checkbox']:checked").map(function() { return this.id });
    console.log('in .change(): ', lyrs)
    legendFunction( lyrs );

});

function legendFunction( lyrs ) {
    map.on('click', function() {
        console.log('in legendFunction: ', lyrs);
    });
};

当我在.change 回调函数中将变量打印到控制台时,存在一个lyrs 对象。但是,当我从legendFunction 中的.on('click') 回调函数打印它时,它会打印一个在每次选中或取消选中复选框时选中的层列表(因为缺少更好的词)。下图显示了这一点:

发生了什么事?如何让.on('click') 函数中的lyrs 变量仅对应于最近的.change() 事件的层?

【问题讨论】:

    标签: javascript jquery onclick click onchange


    【解决方案1】:

    这是因为您每次调用legendFunction 时都将监听器绑定到map 的点击事件。这是因为每次调用该函数时,您将 lyrs 数组作为参数传递(这与您在脚本顶部定义的 lyrs 变量不同)然后您进行绑定,所以您正在创建一个闭包,该闭包会记住该数组在当时以及以后每次调用该函数时的值。

    你的程序基本上是这样做的:

    您选中了 ID 为 landfireEVT 的复选框

    • 在更改回调中,您将拥有lyrs = ['landfireEVT']
    • 当您调用legendFunction 时,您将新绑定添加到map 元素,它会“记住”lyrs = [landfireEVT]
    • 如果你点击map元素,刚刚绑定的事件将会触发,在控制台你会看到lyrs = ['landfireEVT']的值

    现在有人选中了 ID 为 agc 的复选框

    • 在更改回调中,您将拥有lyrs = ['landfireEVT','agc']
    • 当您调用legendFunction 时,您将新绑定添加到map 元素,它会“记住”lyrs = ['landfireEVT','agc']
      • 如果您单击map 元素,之前绑定到 click 事件的第一个回调将触发,您将在控制台中看到 lyrs = ['landfireEVT'],然后是刚刚绑定到点击事件会触发,你会看到lyrs = ['landfireEVT','agc']的值

    我将只绑定一次事件并将更新后的复选框列表保存在 lyrs 变量中

    var lyrs;
    map.on('click', function() {
       //lyrs will always be the variable defined above anytime somebody clicks on the map element.
       console.log('in legendFunction: ', lyrs);
     });
    
    $("div#myID input:checkbox").change(function() {
      lyrs = $("div#myID input[type='checkbox']:checked").map(function() { return this.id });
      //add here any other logic you need to notify somebody else that a checkbox changed.
    });
    

    你可以在这里https://community.risingstack.com/explaining-javascript-closure-scope-chain-examples/阅读更多关于闭包和作用域的信息

    【讨论】:

      【解决方案2】:

      问题是每次单击复选框时都会通过legendFunction 注册Leaflet Event 回调。因此,每次单击地图时,Leaflet 都会使用用于注册回调的lyrs 值执行回调。

      您可能只想注册一个click 事件处理程序。像这样的:

      HTML:

      <div id="layer1" class="layers">
        <input type="checkbox" id="layer1" />
        <label>layer1</label>
      </div>
      
      <div id="layer1" class="layers">
        <input type="checkbox" id="layer2" />
        <label>layer2</label>
      </div>
      
      <div id="mapid"></div>
      

      JavaScript:

      var mymap = L.map('mapid').setView([51.505, -0.09], 8);
      
      mymap.on('click', function() {
        $(".layers input[type='checkbox']:checked").each(function() {
          console.info(this.id, 'is checked');
        });
      });
      

      【讨论】:

        【解决方案3】:

        您的legendFunction 向您的地图添加了一个事件处理程序(它没有显示,但我假设legendFunction 中的map 是一个代表您的实际地图的jQuery 对象)。问题是它每次运行该函数时都会添加一个新的事件处理程序。 From the jQuery documentation:

        从 jQuery 1.4 开始,同一个事件处理程序可以多次绑定到一个元素。

        当触发该事件时,所有这些重复的处理程序都会触发。每次单击复选框时,都会触发您的复选框更改处理程序,该处理程序又会调用legendFunction,从而将新的单击处理程序添加到您的地图中。

        迭代 1

        第一次通过时,lyrs 被设置为选中复选框的 jQuery 对象,它将在控制台上列出。 map 上的点击还没有事件处理程序(除非legendFunction() 在其他地方也被触发,或者如果你在其他地方添加另一个点击处理程序),所以legendFunction(或者更确切地说是@987654330 的事件处理程序@add) 这次不生成任何控制台输出。此迭代添加了第一个 map 点击事件处理程序。

        迭代 2

        下次单击复选框时,您将再次从您的复选框更改处理程序中将正确的lyrs 记录到控制台。您还没有描述它,但是如果您的复选框实际上您的map,那么同样的点击将从复选框冒泡到map,并触发添加的map点击处理程序在迭代 1 中也是如此。根据您的 HTML 结构,lyrs 将使用新的选中复选框集进行更新,并且迭代 1 的 map 点击处理程序的输出将反映这一点。此外,此单击调用 legendFunction(),并添加了第二个重复的 map 单击事件处理程序。

        迭代 3

        如上所述,除了现在 2 个相同的 map 点击处理程序被触发,每个都在控制台上生成输出。添加了第三个重复的map click 事件处理程序。

        ...等

        我不知道确切的目标是什么,但要避免这个问题,只需创建一次 map 点击事件处理程序:

        map.on('click', function() {
            console.log('map was clicked, layers are', lyrs);
        });
        

        【讨论】:

          【解决方案4】:

          您多次重新绑定点击事件。尝试只输出 lyrs 的值,而不是在 legendFunction 中再次绑定点击。

          var lyrs;
          
          $("div#myID input:checkbox").change(function() {
          lyrs = $("div#myID input[type='checkbox']:checked").map(function() { return this.id });
          console.log('in .change(): ', lyrs)
          legendFunction( lyrs );
          
          });
          
          function legendFunction( lyrs ) {
                  console.log('in legendFunction: ', lyrs);
          };
          

          【讨论】:

            【解决方案5】:

            jquery的on方法会在Event Queue中添加一个Event Listener,也就是说,如果你调用on方法五次,它会在Event Queue中添加五个Event Listener。所以,它会调用Event Callback连续五次触发click事件,在使用on方法绑定事件监听器前,应取消所有事件监听器。

            var lyrs;
            
            $("div#myID input:checkbox").change(function() {
                lyrs = $("div#myID input[type='checkbox']:checked").map(function() { return this.id });
                console.log('in .change(): ', lyrs)
                legendFunction( lyrs );
            
            });
            
            function legendFunction( lyrs ) {
                map.off('click')
                map.on('click', function() {
                    console.log('in legendFunction: ', lyrs);
                });
            };

            【讨论】:

              猜你喜欢
              • 2018-02-19
              • 2014-10-14
              • 2011-04-25
              • 2011-06-09
              • 1970-01-01
              • 2015-02-09
              • 2015-01-31
              • 1970-01-01
              • 2018-09-23
              相关资源
              最近更新 更多