【问题标题】:Dynamically appended select menu with 1st option disabled automatically selects 2nd option禁用第一个选项的动态附加选择菜单自动选择第二个选项
【发布时间】:2015-10-12 11:58:30
【问题描述】:

我遇到了一个奇怪的案例,据我所知,两个应该表现相同的东西表现得完全不同。

如果我在一个页面上有两个选择菜单,一个是在 HTML 中硬编码的静态菜单,一个是在运行时使用 JQuery 附加到正文的。然后我禁用两个选择菜单中的第一个选项。显示时,两个菜单都按预期禁用了它们的第一个选项,但是动态附加的菜单会自动将值设置为第二个选项,而静态菜单仍然选择第一个选项。

http://jsfiddle.net/hm3xgkLg/1/

HTML:

<select class="dropMenu">
  <option value="1">First</option>
  <option value="2">Second</option>
  <option value="3">Third</option>
  <option value="4">fourth</option>
</select>

Javascript:

var arr = [
  {val : 1, text: 'One'},
  {val : 2, text: 'Two'},
  {val : 3, text: 'Three'},
  {val : 4, text: 'Four'}
];

var sel = $('<select class="dropMenu">').appendTo('body');
$(arr).each(function() {
   sel.append($("<option>").attr('value',this.val).text(this.text));
 });
$('.dropMenu option:nth-child(1)').attr('disabled', 'disabled');

为什么这两个看似相同的选择菜单表现不同?我希望两者都像静态菜单一样(保持第一个值被选中)这可能吗?

还应注意,我尝试将禁用功能包装在 $(document).ready 中以排除菜单尚未呈现但没有更改的问题。我还尝试使用两个不同的类和两个单独的调用来禁用这些选项,以确保它不会以某种方式发生冲突而没有任何变化。

【问题讨论】:

标签: javascript jquery html drop-down-menu


【解决方案1】:

默认情况下,如果您将选项 selected 赋予动态 dropdown 的第一个选项,那么它会为您完成:

看看这个DEMO

$(arr).each(function(key,value) {
    if(key==0)
         sel.append($("<option>").attr('value',this.val).text(this.text).attr('selected',true));
    else
         sel.append($("<option>").attr('value',this.val).text(this.text));
});

现在为什么会发生这种情况?

对于静态select,该元素已经存在于DOM 中,然后您使用jquery 为第一个option 添加disabled,默认情况下第一个option 将保留为selected .

现在是动态的select,因为你正在添加它dynamically,它可能没有考虑到select,默认情况下是第一个option,因为它被禁用了!!

即使我觉得这是一种奇怪的行为,但有时我们需要通过跟踪和错误来处理这些事情。

【讨论】:

  • 这是肯定的解决方案,但仍然不能解释 OP 发现的奇怪行为。
  • @lucasnadalutti 好吧,我试图尽我所能解释,这是我的观点,或者我可以说这就是我可以扩展我的知识的!如果有人对此有更好的了解,请随时欢迎.. :)
  • 这确实适用于给定的场景,但实际上我没有使用简单的数组来填充下拉列表,它是从服务器中提取并作为数组添加到 Knockout.js 模板的 JSON 数据所以我不能在我的情况下使用这个解决方案。我只是为了说明这一点而对其进行了简化,因为它具有相同的结果。如果我找不到可用的解决方案,但我会接受你的解决方案,因为它确实满足给定的问题。
【解决方案2】:

为什么这两个看似相同的选择菜单的行为 不一样

这是因为第一个 select 已经是文档的一部分并且已被解析。 As per the spec here

初始状态选择了第一个选项..

因此第一个选项是预先选择的。稍后当您禁用一个选项时,它不会更改选择。

示例 1:您可以看到第一个 select 已将 disabled 属性应用于标记中的第一个选项。与第二个 select 相比,第二个选项是预先选择的。

<select class="dropMenu">
    <option value="1" disabled>First</option>
    <option value="2">Second</option>
    <option value="3">Third</option>
    <option value="4">fourth</option>
</select>
<select class="dropMenu">
    <option value="1">First</option>
    <option value="2">Second</option>
    <option value="3">Third</option>
    <option value="4">fourth</option>
</select>

在您使用 Javascript 动态添加 select 的情况下,第二个 select 已创建并立即添加到 body。当这成为 DOM 的一部分时,没有选项,因此不可能进行预选。稍后当您将选项附加到它,然后禁用其中一个选项时,它似乎执行得太快,并且在加载时第一个选项已被禁用,而第二个选项已被预先选择。

示例 2:不要将 select 立即附加到 body。在填充了 options 后附加它。这一次将预先选择第一个 option,尽管您稍后更改了 disabled 属性。

var arr = [
  {val : 1, text: 'One'},
  {val : 2, text: 'Two'},
  {val : 3, text: 'Three'},
  {val : 4, text: 'Four'}
];

var sel = $('<select class="dropMenu">');
$(arr).each(function () {
    sel.append($("<option>").attr('value', this.val).text(this.text));
});

sel.appendTo('body'); /* <--- append here */

$('.dropMenu option:nth-child(1)').prop('disabled', true);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<select class="dropMenu">
    <option value="1">First</option>
    <option value="2">Second</option>
    <option value="3">Third</option>
    <option value="4">fourth</option>
</select>

示例 3:在 disableoption 之前添加延迟。这将为您提供预选第一个 option 的预期行为,因为它将有足够的时间。

var arr = [
  {val : 1, text: 'One'},
  {val : 2, text: 'Two'},
  {val : 3, text: 'Three'},
  {val : 4, text: 'Four'}
];

var sel = $('<select class="dropMenu">').appendTo('body');
$(arr).each(function () {
    sel.append($("<option>").attr('value', this.val).text(this.text));
});

setTimeout(disable, 1000); /* <--- give some delay here */

function disable() {
    $('.dropMenu option:nth-child(1)').prop('disabled', true);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<select class="dropMenu">
    <option value="1">First</option>
    <option value="2">Second</option>
    <option value="3">Third</option>
    <option value="4">fourth</option>
</select>

示例 4:您还可以在禁用 option 之前明确选择它们。

var arr = [
  {val : 1, text: 'One'},
  {val : 2, text: 'Two'},
  {val : 3, text: 'Three'},
  {val : 4, text: 'Four'}
];

var sel = $('<select class="dropMenu">').appendTo('body');
$(arr).each(function () {
    sel.append($("<option>").attr('value', this.val).text(this.text));
});

$('.dropMenu option:nth-child(1)').prop('selected', true); /* <-- select explicitly */
$('.dropMenu option:nth-child(1)').prop('disabled', true);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<select class="dropMenu">
    <option value="1">First</option>
    <option value="2">Second</option>
    <option value="3">Third</option>
    <option value="4">fourth</option>
</select>

【讨论】:

    【解决方案3】:

    只需手动选择动态添加菜单中的第一个选项:

    $('.dropMenu option:nth-child(1)')
          .attr('disabled', 'disabled')
          .attr('selected', 'selected');
    

    jsfiddle 在这里(我借了你的:P): https://jsfiddle.net/z0dzk5nL/1/

    编辑 快速更新。 Here 您可以找到“选择”元素的规范。我引用了回答您问题的部分:

    如果插入节点或删除节点导致选项列表 获得或失去一个或多个选项元素,或者如果一个选项元素 在选项列表中要求重置,然后,如果选择元素的 多个属性不存在,用户代理必须运行第一个 以下列表中适用的一组步骤:

    如果select元素的显示大小为1,并且没有option元素 选择元素的选项列表的选择度设置为 true 设置列表中第一个选项元素的选择度 未禁用的树顺序选项(如果有)为 true。

    如果选择元素的选项列表中有两个或多个选项元素 将他们的选择设置为真 列表中最后一个 option 元素的选择性设置为 true 树顺序中的选项为 false。

    这里的小提琴表明,如果您在附加选项时预先选择该选项,则可以在不丢失选择的情况下禁用(我使用 for 循环而不是“每个”函数来证明这一点):

    jsfiddle.net/xnvbevhm/

    (对不起,我不能发布超过两个链接,因为我没有足够的声誉:P)

    【讨论】:

      【解决方案4】:

      作为将第一个属性设置为选中的替代方法,使用 setTimeout 和最短时间(即 1)似乎可以使事情按预期运行。不过,我仍在研究其中的原因。

      setTimeout(function() {
          $('.dropMenu option:nth-child(1)').attr('disabled', 'disabled');
      }, 1);
      

      Updated fiddle.

      【讨论】:

        【解决方案5】:

        尝试在setInterval 中设置您的$('.dropMenu option:nth-child(1)').attr('disabled', 'disabled');,因为您正在创建动态下拉列表,因此执行和创建需要一些时间,同时您 禁用 jquery 将执行的下拉元素。所以问题来了。

        结帐代码片段

        var arr = [
          {val : 1, text: 'One'},
          {val : 2, text: 'Two'},
          {val : 3, text: 'Three'},
          {val : 4, text: 'Four'}
        ];
        
        var sel = $('<select class="dropMenu">').appendTo('body');
        $(arr).each(function() {
           sel.append($("<option>").attr('value',this.val).text(this.text));
         });
        
        
        setTimeout(function() {
            $('.dropMenu option:nth-child(1)').attr('disabled', 'disabled');
        }, 1);
        <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
        <select class="dropMenu">
          <option value="1">First</option>
          <option value="2">Second</option>
          <option value="3">Third</option>
          <option value="4">fourth</option>
        </select>

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2022-10-17
          • 1970-01-01
          • 1970-01-01
          • 2016-11-07
          • 1970-01-01
          • 2023-02-23
          相关资源
          最近更新 更多