gpt4 book ai didi

javascript - 从选择中删除选项并重新附加选定的更改

转载 作者:太空狗 更新时间:2023-10-29 13:49:28 24 4
gpt4 key购买 nike

在删除和重新附加选项到选择元素时,我刚刚意识到一个奇怪的行为。碰巧的是,如果选择了其中一个选项,在附加后,下一个项目将被选中,而不是原来的项目。考虑以下 html:

var $opts = $("#sel option").remove();
console.log($opts);
$("#sel").append($opts);
<select id="sel">
<option>A</option>
<option>B</option>
<option selected="selected">C</option>
<option>D</option>
</select>
(Look in the console.)
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>


(或作为 fiddle )

它使选项具有值 "D"被选中,而不是具有值 "C" 的选项,如最初定义。注意控制台中打印的选项,属性 selected remove() 后更改方法。

为什么会这样?

注:我知道如何修复它或解决它,这不是问题。问题是为什么会发生?

最佳答案

迷人的问题。

我相信这取决于浏览器在删除唯一选定的选项时自动选择一个选项,然后当您将选项添加到具有 selected 的框中时会发生什么。标志设置。它似乎也是特定于浏览器的,这可能不会让我们感到惊讶。但更重要的是,Chrome 会根据我们观察的密切程度改变其行为。这确实让我感到惊讶。详情如下。

首先,让我们使用类似于您更新的示例的内容,但是我们从 selected 开始的那个既不是第一个也不是最后一个,然后看看我们在哪里结束。所以我们将有 A、B、C、D 和 E,并从选择 B 开始:

$("input[type=button]").on("click", function() {
var $opts = $("#sel option").remove();
$("#sel").append($opts);
});
<select id="sel">
<option>A</option>
<option selected="selected">B</option>
<option>C</option>
<option>D</option>
<option>E</option>
</select>
<input type="button" value="Go">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>


我们观察到的结果因浏览器而异:
  • Chrome 最终出现在 C 上,这是一开始选择的一个(不是最后一个)。
  • IE11 最终在 B 上,也就是说,当我们删除/添加时,它似乎没有更改选定的标志。
  • Firefox 最终出现在 E(最后一个)上。

  • 更糟糕的是,Chrome 的行为取决于我们是否观察到 selected元素的属性,因为这是否发生。海森堡!如果我们观察它,它最终会做 Firefox 所做的(E)而不是 C。

    这为我们提供了有关 Chrome 中发生的事情的重要线索。但让我们从简单的开始:

    IE11

    看起来 IE11 只是不理会这些标志,可能是因为它不担心在 JavaScript 代码运行时更新它们,只有当它返回并且 IE 更新其 UI 时才会更新它们。

    火狐

    如果 Firefox 主动设置 selected,它就有意义。当框中未选择任何选项时在选项上标记(因为我们删除了选定的选项):
  • 我们去掉A,B保持选中状态。
  • 我们移除 B,C 被选中,因为 B 不再在框中,并且该框需要至少有一个被选中的选项。已删除选项的标志保持设置,这一点很重要
  • 当我们删除 C 和 D 时,重复步骤 2。
  • 我们移除 E。此时,C、D 和 E 都设置了标志。
  • 我们将 A 添加到框中。因为它是盒子唯一的选项,所以它得到了 selected标志设置。
  • 我们将 B 添加到框中。由于B的selected标志被设置,它成为选定的属性,A 被取消选择。
  • 当我们添加 C、D 和 E 时,重复步骤 6。
  • 我们最终选择了 E。

  • 我们可以观察 IE11 和 Firefox 发生的情况,因为它们不会根据我们是否观察到它们而改变它们的行为:

    var $opts = $("#sel option");
    showOptions("Before", $opts);
    $opts.each(function() {
    var opt = $(this);
    opt.remove();
    showOptions("After removing " + opt.text(), $opts);
    });
    $opts.each(function() {
    var opt = $(this);
    $("#sel").append(opt);
    showOptions("After appending " + opt.text(), $opts);
    });
    function showOptions(label, $opts) {
    var row = $("<tr>");
    row.append($("<td>").text(label).addClass("label"));
    $opts.each(function() {
    row.append($("<td>").text(this.selected ? "*" : "o"));
    });
    row.appendTo("#results");
    }
    th, td {
    min-width: 3em;
    text-align: center;
    padding: 4px;
    }
    table, th, td {
    border-collapse: collapse;
    border: 1px solid #eee;
    }
    .label {
    text-align: left;
    }
    <select id="sel">
    <option>A</option>
    <option selected="selected">B</option>
    <option>C</option>
    <option>D</option>
    <option>E</option>
    </select>
    <table>
    <thead>
    <tr>
    <th></th>
    <th>A</th>
    <th>B</th>
    <th>C</th>
    <th>D</th>
    <th>E</th>
    </tr>
    </thead>
    <tbody id="results">
    </tbody>
    </table>
    * = selected, o = not selected

    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>


    Chrome 合金

    这给我们带来了困难:Chrome。 Chrome 会根据我们是否观察到 selected 来改变其行为。我们去的时候属性(property)。具体来说,如果我们观察 selected,它会改变它的行为。在我们删除它们时仍在选择框中的选项。不管我们看 selected在删除的那些上,我们不关心我们是否查看 selected正如我们正在追加。就像我们正在删除,只是那些我们还没有删除。

    首先,这里有证据:

    $("#btn").on("click", function() {
    var observeLTE = true;
    var observeGT = true;
    var index;
    var $opts = $("#sel option");
    showOptions("Before", $opts);
    observeLTE = $("#cbremove")[0].checked;
    observeGT = $("#cbremoveun")[0].checked;
    $opts.each(function(i) {
    var opt = $(this);
    index = i;
    opt.remove();
    showOptions("After removing " + opt.text(), $opts);
    });
    observeLTE = observeGT = $("#cbappend")[0].checked;
    $opts.each(function(i) {
    var opt = $(this);
    index = i;
    $("#sel").append(opt);
    showOptions("After appending " + opt.text(), $opts);
    });

    function showOptions(label, $opts) {
    var row = $("<tr>");
    row.append($("<td>").text(label).addClass("label"));
    $opts.each(function(i) {
    var selected;
    if ((observeLTE && i <= index) || (observeGT && i > index)) {
    selected = this.selected ? "*" : "o";
    } else {
    selected = "-";
    }
    row.append($("<td>").text(selected));
    });
    row.appendTo("#results");
    }
    });
    th, td {
    min-width: 3em;
    text-align: center;
    padding: 4px;
    }
    table, th, td {
    border-collapse: collapse;
    border: 1px solid #eee;
    }
    .label {
    text-align: left;
    }
    <div>
    <label>
    <input id="cbremove" type="checkbox">Observe <code>selected</code> on removed options while removing
    </label>
    </div>
    <div>
    <label>
    <input id="cbremoveun" type="checkbox">Observe <code>selected</code> on UNremoved options while removing
    </label>
    </div>
    <div>
    <label>
    <input id="cbappend" type="checkbox">Observe <code>selected</code> while appending
    </label>
    </div>
    <select id="sel">
    <option>A</option>
    <option selected="selected">B</option>
    <option>C</option>
    <option>D</option>
    <option>E</option>
    </select>
    <input id="btn" type="button" value="Go">
    <table>
    <thead>
    <tr>
    <th></th>
    <th>A</th>
    <th>B</th>
    <th>C</th>
    <th>D</th>
    <th>E</th>
    </tr>
    </thead>
    <tbody id="results">
    </tbody>
    </table>
    * = selected, o = not selected, - = not observed

    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>


    如果你试一试(显然在 Chrome 上),你会注意到无论你对第一个或最后一个复选框做什么,你最终都会在 C 上,但是选中中间的复选框会让你最终在 E 上。

    这为我们提供了足够的数据来推断解释。我真的不能说 解释,只是它符合可用数据。如果有人想要更彻底,他们可以在调试版本中逐步浏览 Chrome 的内部代码。我认为这太过分了。

    所以这是我的答案,我再次强调推断:
  • Chrome 设置 selected HTMLOptionElement 上的属性(property)实例懒洋洋地 .也就是说,如果您不读取该属性的值,Chrome 不会检查以确保该属性反射(reflect)当前状态。
  • 它读取 selected排队时的属性 change事件。
  • 它不会排队 change事件,如果该选择框已经挂起。

  • 基于此,我认为 Chrome 会发生以下情况:
  • 我们去掉A,B保持选中状态。否 change事件,因为值没有改变。
  • 我们移除 B,C 被选中,因为 B 不再在框中,并且该框需要至少有一个被选中的选项。这将排队 change事件,观察 selected并因此在 C 上设置属性。
  • 我们删除了 C。 D 被选中(在某种意义上),但因为有一个 change事件待处理,无新 change事件已排队,因此 D 的 selected未观察到且其值未更新;它仍然false即使 如果 我们阅读它,它会变成true .
  • 删除 D 时再次相同。没有变化事件,没有观察。
  • 我们最终得到了具有 selected 的选项元素如 true在 B 和 C 上,但其他都没有,因为 D 和 E 在被选中时没有被观察到,并且没有更新它们的值。我们知道这些是他们的值(value)观,因为我们在那个时候被允许观察他们。
  • 我们按顺序添加元素,与 Firefox 一样,添加具有 selected = true 的元素。当另一个元素已被选择时,取消选择前一个元素。所以在添加 C 时取消选择 B。当我们添加 D 和 E 时,C 被保留下来,因为它们的 selected属性是 false .

  • ,这很有趣。

    关于javascript - 从选择中删除选项并重新附加选定的更改,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32782564/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com