因此,当我在相邻的下拉列表中进行某个选择时,我会尝试在一个下拉列表中禁用某些日期。我有20对这些下拉菜单。当它只有1对而不是两者时,我可以让它工作。所以当" month1"被选中,我需要在" day1"无法使用。
data = {
disabled_days: {
"June": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 17, 18, 24, 25, 31],
"July": [1, 2, 3, 4, 8, 9, 15, 16, 22, 23, 29, 30],
"August": [5, 6, 12, 13, 19, 20, 26, 27]
}
}
//loop through to create this 20 times
for(x=1;x<=20;x++){
//get the select month box
let select_month = document.querySelector('select[name="month'+x+'"]');
//when month is selected
select_month.addEventListener('change', function(e){
//get the name of the month
let month = select_month[select_month.selectedIndex].textContent;
//get all the days in the data select box and enable them all
let day_arr = [].slice.call(document.querySelectorAll('select[name="day'+x+'"] option'))
for(let day of day_arr) day.disabled = false;
//loop over all the days to be disabled, find thme in the data ovject based on month and disable those days
for (let disabled_day of data.disabled_days[month]){
for (let day of day_arr){
if (day.textContent == disabled_day) day.disabled = true;
}
}
})
}
所以我觉得我在串联('select[name="day'+x+'"] option')
的某个地方发生了故障,并且月份也一样。
这已经让我搞砸了差不多一个星期,所以任何帮助都会非常感激。
这是关联的php和html:
<?php for($x=1; $x<=20; $x++){ ?>
<div class="form-group">
<label><?php echo "$x"; ?>.</label>
<select class="form-control" name="month<?php echo $x ;?>">
<option selected disabled>- Month -</option>
<option value="06">June</option>
<option value="07">July</option>
<option value="08">August</option>
</select>
<select class="form-control" name="day<?php echo $x ;?>">
<option selected disabled>- Day -</option>
<option value="01">1</option>
<option value="02">2</option>
<option value="03">3</option>
<option value="04">4</option>
<option value="05">5</option>
<option value="06">6</option>
<option value="07">7</option>
<option value="08">8</option>
<option value="09">9</option>
<option value="10">10</option>
<option value="11">11</option>
<option value="12">12</option>
<option value="13">13</option>
<option value="14">14</option>
<option value="15">15</option>
<option value="16">16</option>
<option value="17">17</option>
<option value="18">18</option>
<option value="19">19</option>
<option value="20">20</option>
<option value="21">21</option>
<option value="22">22</option>
<option value="23">23</option>
<option value="24">24</option>
<option value="25">25</option>
<option value="26">26</option>
<option value="27">27</option>
<option value="28">28</option>
<option value="29">29</option>
<option value="30">30</option>
<option value="31">31</option>
</select>
</div> <?php } ?>
答案 0 :(得分:0)
好的,因此有几个原因导致您遇到下拉菜单无法正确禁用的问题:
首先我注意到如果您提供的js代码保留原样,以下调用将返回一个空数组:
let select_month = document.querySelector('select[name="month'+x+'"]');
这可能会因您的浏览器呈现DOM并运行脚本的速度而改变,但一般来说,运行for循环时无法保证选择菜单和选项。因此,您应该使用DOMContentLoaded事件(要遵循的代码)包装main for循环,以确保它仅在加载DOM后运行。如果您正在使用jQuery,您可以将整个事物包装在$(document).ready(...)
函数中。
其次,您可以替换以下行:
let day_arr = [].slice.call(document.querySelectorAll('select[name="day'+x+'"] option'))
只有:
let day_arr = document.querySelectorAll('select[name="day'+idx+'"] option');
querySelectorAll
已经返回了一个可以迭代的数组。您还会注意到我有变量idx
而不是x
。这是由于第三个更令人困惑的原因。
在javascript中使用var
声明的变量不是块作用域(您可以在es6中使用let
来避免这种情况),它们的作用域是定义它们的函数,或者全局作用域。这意味着在你的main for循环中:for(x=1;x<=20;x++)
变量的范围没有被定义为在for循环块中,就像c / c ++,java,c#这样的语言,它被定义为包围它的功能范围。在这种特殊情况下,没有包含它的功能,因此它与全局对象相似。因此,结果如下:
当for循环运行时,它会遍历该块并执行所有代码,其中一个代码正在注册此事件监听器:
select_month.addEventListener('change', function(e){})
此事件侦听器是一个异步调用,这意味着它在for循环运行时不会被执行,它只被声明并注册到一个事件。这意味着当它最终运行时,在更改事件之后,for循环早已完成。但是,此更改事件函数在以下行中引用了x
:
document.querySelectorAll('select[name="day'+x+'"] option')
当它最终运行这段代码时,它在当前时间获得x的值,就在for循环完成之后,这意味着它的值为21
。它在循环完成后可以访问x
值,因为正如我们所讨论的那样,变量没有作用于for循环,它存在于它之外。因此,对于此事件的所有调用,x
将为21
,无论您选择哪个下拉列表。由于21
不是有效日期名称的一部分,因此数组将始终为空。
解决方法是将change事件调用包装在自己的函数中,并将x
的值作为参数传递给这个新函数,我们称之为idx
。该函数将立即声明并执行。请注意,即使运行该函数,更改事件仍然只是注册,而不是执行。现在querySelector语句将引用函数参数而不是x
变量。由于函数参数是针对每个循环执行的,因此每次都传递一个新值x
,因此每个更改事件侦听器的参数也是新的。您之前可能已经看过这种模式,它被称为闭包。
我已经更新了你的代码,看看:
var data = {
disabled_days: {
"June": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 17, 18, 24, 25, 31],
"July": [1, 2, 3, 4, 8, 9, 15, 16, 22, 23, 29, 30],
"August": [5, 6, 12, 13, 19, 20, 26, 27]
}
}
//On DOM Loaded
document.addEventListener("DOMContentLoaded", function(event) {
//loop through to create this 20 times
for(x=1;x<=20;x++){
//get the select month box
let select_month = document.querySelector('select[name="month'+x+'"]');
//A colusure to wrap the change event listener, this is done
//to pass the current value of x into the listener
(function(idx){
//when month is selected
select_month.addEventListener('change', function(e){
//get the name of the month
let month = select_month[select_month.selectedIndex].textContent;
//get all the days in the data select box and enable them all
let day_arr = document.querySelectorAll('select[name="day'+idx+'"] option');
for(let day of day_arr) day.disabled = false;
//loop over all the days to be disabled, find thme in the data ovject based on month and disable those days
for (let disabled_day of data.disabled_days[month]){
for (let day of day_arr){
if (day.textContent == disabled_day) day.disabled = true;
}
}
})
})(x);
}
});
最后,您应该重新考虑代码中的逻辑。它有很多低效和不必要的部分,特别是在事件监听器中。您当前正在调用2个for循环,其中一个是嵌套的,每次在20个下拉列表中的任何一个上选择一个月。没有必要这样做,你应该只在加载DOM时禁用相关选项,并且永远不必在更改事件上循环它。您必须考虑数据的状态以及改变它的事件;选择月份下拉列表对禁用的天数对象没有影响,因此您不必更新任何依赖此数据的元素。