IE 在 DOM 操作有表单控件时的 bug

bug 描述

  • 影响的范围: IE 的所有版本
  • 在表单的 radio/checkbox 控件中,一旦他们的 DOM 结构被更改过就会出现这个 bug 。
  • 操作了表单 radio/checkbox 的 DOM 结构时(或者直接影响了他们的结构时)选中的 checkbox/radio 将会自动恢复到默认状态,
  • 有如点了 reset 按钮一样。

bug 重现

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" 
"http://www.w3.org/TR/html4/strict.dtd">
<html>
 <head>
 <title>Rank's HTML document</title>
 <meta http-equiv="Content-Type" content="text/html; charset=gb2312" />
 <meta http-equiv="Pragma" content="no-cache" /> 
 <style type="text/css" title="default" media="screen">
 /*<![CDATA[*/
      body { font-size:80%; line-height:1.5; }
      body, button { font-family:arial; }
      button { padding:0 0.3em 0 0.3em; }
      h1, h3 { margin:0; padding:0; }
      h1 { font-size:2.3em; }
      h3 { font-size:1.3em; }
      form { display:inline-block; }
      div.link { padding:1em; }
      div.content { background:#ffc; padding:1em; border:1px solid #222; margin:1em 0 1em; }
      #rdoWrapper { }
      #hd { text-align:center; }
 /*]]>*/
 </style>
 </head>
 <body>
    <div id="hd">
      <h1> IE form control bug </h1>
      <div class="link">from: <a href="http://www.never-online.net/blog"><em>never-online weblog</em></a></div>
    </div>
    <div id="rdoWrapper" class="content">
      <h3> 1. Select radio to checked </h3>
      <form method="post">
      <input type="radio" name="rdo" id="rdo-1" value="rdo-1" checked><label for="rdo-1">radio1</label>
      <input type="radio" name="rdo" id="rdo-2" value="rdo-2"><label for="rdo-2">radio2</label>
      <input type="radio" name="rdo" id="rdo-3" value="rdo-3"><label for="rdo-3">radio3</label>
      <input type="radio" name="rdo" id="rdo-4" value="rdo-4"><label for="rdo-4">radio4</label>
      </form>
    </div>
    <div class="content">
      <h3> 2. Click button to change dom structure </h3>
        <p class="p"><button type="button" onclick="handleChangeDom()">test</button></p>
    </div>
    <script type="text/javascript">//<![CDATA[
      function getRadioValue(ctlName) {
        var ctls = document.getElementsByName(ctlName);
        var len = ctls.length;
        for (var i=0; i<len; i++) {
          if (ctls[i].checked) {
            return ctls[i].value;
          }
        }
      }
      function handleChangeDom() {
        alert('before append, you select radio value is "'+getRadioValue('rdo')+'"');
        var wrapper = document.getElementById('rdoWrapper');
        document.body.appendChild(wrapper);
        alert('after append, you select radio value is "'+getRadioValue('rdo')+'"');
      }
    //]]></script>
 </body>
</html>

解决方法

可以在操作 DOM 之前,用 「 defaultChecked 」 来设置 checked 的值。

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" 
"http://www.w3.org/TR/html4/strict.dtd">
<html>
 <head>
 <title>Rank's HTML document</title>
 <meta http-equiv="Content-Type" content="text/html; charset=gb2312" />
 <meta http-equiv="Pragma" content="no-cache" /> 
 <style type="text/css" title="default" media="screen">
 /*<![CDATA[*/
      body { font-size:80%; line-height:1.5; }
      body, button { font-family:arial; }
      button { padding:0 0.3em 0 0.3em; }
      h1, h3 { margin:0; padding:0; }
      h1 { font-size:2.3em; }
      h3 { font-size:1.3em; }
      form { display:inline-block; }
      div.link { padding:1em; }
      div.content { background:#ffc; padding:1em; border:1px solid #222; margin:1em 0 1em; }
      #rdoWrapper { }
      #hd { text-align:center; }
 /*]]>*/
 </style>
 </head>
 <body>
    <div id="hd">
      <h1> fixed IE form control bug </h1>
      <div class="link">from: <a href="http://www.never-online.net/blog"><em>never-online weblog</em></a></div>
    </div>
    <div id="rdoWrapper" class="content">
      <h3> 1. Select radio to checked </h3>
      <form method="post">
      <input type="radio" name="rdo" id="rdo-1" value="rdo-1" checked><label for="rdo-1">radio1</label>
      <input type="radio" name="rdo" id="rdo-2" value="rdo-2"><label for="rdo-2">radio2</label>
      <input type="radio" name="rdo" id="rdo-3" value="rdo-3"><label for="rdo-3">radio3</label>
      <input type="radio" name="rdo" id="rdo-4" value="rdo-4"><label for="rdo-4">radio4</label>
      </form>
    </div>
    <div class="content">
      <h3> 2. Click button to change dom structure </h3>
        <p class="p"><button type="button" onclick="handleChangeDom()">test</button></p>
    </div>
    <script type="text/javascript">//<![CDATA[
      function getRadioValue(ctlName) {
        var ctls = document.getElementsByName(ctlName);
        var len = ctls.length;
        for (var i=0; i<len; i++) {
          if (ctls[i].checked) {
            return ctls[i].value;
          }
        }
      }
      function setRadioDefaultValue(ctlName) {
        var ctls = document.getElementsByName(ctlName);
        var len = ctls.length;
        for (var i=0; i<len; i++) {
          ctls[i].defaultChecked = ctls[i].checked;
        }
      }
      function handleChangeDom() {
        alert('before append, you select radio value is "'+getRadioValue('rdo')+'"');
        setRadioDefaultValue('rdo');
        var wrapper = document.getElementById('rdoWrapper');
        document.body.appendChild(wrapper);
        alert('after append, you select radio value is "'+getRadioValue('rdo')+'"');
      }
    //]]></script>
 </body>
</html>

-- EOF --

Comments