我在解决一个基本问题时遇到了麻烦,但是甚至无法弄清楚研究的正确用语是什么。
本质上,我有一个.change()
监听器,用于监听div
内的复选框的更改(它们切换Leaflet Map图层)。我想创建一个变量来保存已选中复选框的列表。我可以这样做,但是,对于.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
对象。但是,当我从.on('click')
中的legendFunction
回调函数打印它时,它会打印一个列表(缺少更好的单词),每次检查或取消选中复选框时都会检查这些图层。下图显示了这一点:
发生了什么事?如何让lyrs
函数中的.on('click')
变量仅对应于最近.change()
个事件的图层?
答案 0 :(得分:0)
问题是,每次点击复选框时,都会通过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');
});
});
答案 1 :(得分:0)
您的legendFunction
为地图添加了一个事件处理程序(它没有显示但我假设map
中的legendFunction
是一个表示实际地图的jQuery对象)。问题是它每次运行该函数时都会添加一个新的事件处理程序。 From the jQuery documentation:
从jQuery 1.4开始,同一个事件处理程序可以多次绑定到一个元素。
当触发该事件时,所有这些重复的处理程序都会触发。每次单击复选框时,都会触发复选框更改处理程序,然后调用legendFunction
,这会向地图添加新的单击处理程序。
迭代1
第一次,lyrs
被设置为已选中复选框的jQuery对象,它将在控制台上列出。对于map
的点击没有事件处理程序(除非legendFunction()
在其他地方也被触发,或者如果你在其他地方添加另一个点击处理程序),那么legendFunction
(或者更确切地说) legendFunction
添加的事件处理程序这次不会生成任何控制台输出。此迭代添加了第一个map
单击事件处理程序。
迭代2
下次单击一个复选框时,您将再次从复选框更改处理程序中获取正确的lyrs
登录到控制台。您还没有对其进行描述,但如果您的{{1>}上的复选框实际上是 ,则相同的点击会从复选框冒出来map
,然后触发map
也在迭代1中添加了单击处理程序。根据您的HTML结构,map
已经使用新的复选复选框进行更新,迭代1 lyrs
点击处理程序的输出将反映出来。此外,此次点击会调用map
,并会添加第二个重复的legendFunction()
点击事件处理程序。
迭代3
如上所述,除了现在激发2个相同的map
点击处理程序,每个处理程序在控制台上生成输出。添加了第三个重复的map
点击事件处理程序。
......等
我不知道目标到底是什么,但为了避免这个问题,只需创建一次map
点击事件处理程序:
map
答案 2 :(得分:0)
您多次重新绑定点击事件。尝试只输出lyrs的值,而不是再次在legendFunction中绑定点击。
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="collapse navbar-collapse" id="myNavbar">
<ul class="nav navbar-nav top-nav pull-right">
<div class="dropdown">
<li class="dropbtn"><a href="#"><i class="fa fa-chevron-down" aria-hidden="true"></i> About Us</a></li>
<div class="dropdown-content">
<a href="https://www.yahoo.com/">Action</a>
<a href="#">Another action</a>
<a href="#">Something else here</a>
<a href="#">Separated link</a>
<a href="#">One more separated link</a>
</div>
</div>
<div class="dropdown">
<li class="dropbtn"><a href="#"><i class="fa fa-chevron-down" aria-hidden="true"></i> Providers</a></li>
<div class="dropdown-content">
<a href="#">Action</a>
<a href="#">Another action</a>
<a href="#">Something else here</a>
<a href="#">Separated link</a>
<a href="#">One more separated link</a>
</div>
</div>
<div class="dropdown">
<li class="dropbtn"><a href="#"><i class="fa fa-chevron-down" aria-hidden="true"></i> Payors</a></li>
<div class="dropdown-content">
<a href="#">Action</a>
<a href="#">Another action</a>
<a href="#">Something else here</a>
<a href="#">Separated link</a>
<a href="#">One more separated link</a>
</div>
</div>
<div class="dropdown">
<li class="dropbtn"><a href="#"><i class="fa fa-chevron-down" aria-hidden="true"></i> Employers</a></li>
<div class="dropdown-content">
<a href="#">Action</a>
<a href="#">Another action</a>
<a href="#">Something else here</a>
<a href="#">Separated link</a>
<a href="#">One more separated link</a>
</div>
</div>
<div class="dropdown">
<li class="dropbtn"><a href="#"><i class="fa fa-chevron-down" aria-hidden="true"></i> Patients</a></li>
<div class="dropdown-content">
<a href="#">Action</a>
<a href="#">Another action</a>
<a href="#">Something else here</a>
<a href="#">Separated link</a>
<a href="#">One more separated link</a>
</div>
</div>
</ul>
</div>
答案 3 :(得分:0)
on
方法会向事件队列添加一个事件监听器,也就是说,如果你调用on
方法五次,它会向事件队列添加五个事件监听器。所以,它触发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);
});
};
&#13;
答案 4 :(得分:0)
这是因为每次调用map
时,您都会将侦听器绑定到legendFunction
的点击事件。这是因为每次调用该函数时,都会将lyrs
数组作为参数传递(与脚本顶部定义的lyrs
变量不同),然后执行绑定,因此您正在创建一个闭包,该闭包会记住该数组在该时间以及随后每次调用该函数时的值。
你的程序基本上是这样做的:
您选中了标识为landfireEVT
lyrs = ['landfireEVT']
legendFunction
时,您会向map
元素添加新的绑定,并且它会记住&#34; lyrs = [landfireEVT]
map
元素,刚刚绑定的事件将会触发,在控制台中您会看到lyrs = ['landfireEVT']
现在有人选中了标识为agc
lyrs = ['landfireEVT','agc']
legendFunction
时,您会向map
元素添加新的绑定,并且它会记住&#34; 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/