EKsumic's Blog

let today = new Beginning();

Click the left button to use the catalog.

OR

為何在舊 IE 中讀得到值,而在 Chrome/Firefox/Edge 中失敗?

在開發 Web 項目時,我們經常需要操作 HTML 表單中的元素。當表單內有多個同名元素時,不同瀏覽器對於這些元素集合的處理方式可能會大不相同。這篇文章將聚焦於舊版 IE 和現代瀏覽器(如 Chrome、Firefox、Edge)之間的行為差異,並解釋為什麼在舊版 IE 中可以讀取集合的 value 屬性,而在現代瀏覽器中會失敗。

問題現象

假設我們有如下的 HTML 結構:

<form id="myForm">
  <input type="text" name="test" value="初始值 1">
  <input type="text" name="test" value="初始值 2">
  <input type="text" name="test" value="初始值 3">
</form>

在 JavaScript 中,當我們執行以下代碼時:

console.dir(document.forms[0].test);
console.log(document.forms[0].test.value);

結果對比

  • 舊版 IE

    • console.dir(document.forms[0].test) 返回一個 HTMLCollection,並包含一個名為 value 的屬性。

    • console.log(document.forms[0].test.value) 正常輸出集合層級的 value 值。

  • 現代瀏覽器(Chrome/Firefox/Edge)

    • 返回的是一個 RadioNodeList(或類似結構),但 value 屬性僅在集合是 radiocheckbox 時有效。

    • name 屬性對應多個元素時,直接訪問 value 通常會失敗,或者返回空值。

行為差異的原因

1. 舊版 IE 的兼容性處理

在舊版 IE 中,document.forms[0].test 返回一個 HTMLCollection,並附加了一些非標準的屬性或方法以支持開發者的早期代碼需求。這包括:

  • value 的特殊處理 當表單內有多個同名元素時,HTMLCollection.value 默認與集合中的第一個元素綁定。當你讀取或賦值 HTMLCollection.value 時,實際上是在操作第一個元素的 value

  • 歷史原因 早期的瀏覽器為了簡化操作,允許開發者通過集合直接訪問某些屬性,而不必顯式操作集合內的具體元素。

2. 現代瀏覽器的標準化行為

現代瀏覽器(如 Chrome、Firefox、Edge)嚴格遵循 DOM 標準:

  • RadioNodeList 替代 HTMLCollectiondocument.forms[0].test 對應多個同名元素時,現代瀏覽器會返回一個 RadioNodeList。這是一種更智能的結構,專為支持 radiocheckbox 類型的元素聚合。

  • value 的限制RadioNodeList 中,value 僅對應選中的 radiocheckbox 的值。對於其他類型的元素集合(如多個 text),value 不適用,返回空值或 undefined。

  • 避免模糊行為 現代瀏覽器更傾向於讓開發者顯式操作集合內的每個元素,而非依賴於集合層級的屬性。

3. 聚合屬性的消失

在標準化的 DOM API 中,集合(無論是 HTMLCollection 還是 RadioNodeList)的屬性和行為被限制在純粹的集合操作範疇。這意味著:

  • 集合層級不再暴露非標準的屬性(如 value)。

  • 開發者需要遍歷集合,顯式操作子元素。

如何寫出跨瀏覽器兼容的代碼

為了避免依賴非標準的集合層級屬性,我們可以顯式操作集合內的具體元素。以下是兩種推薦的做法:

方法 1:使用索引操作

const collection = document.forms[0].test;
for (let i = 0; i < collection.length; i++) {
  console.log(`子元素 ${i} 的 value:`, collection[i].value);
}

方法 2:使用 querySelectorAll

const inputs = document.querySelectorAll('input[name="test"]');
inputs.forEach((input, index) => {
  console.log(`子元素 ${index} 的 value:`, input.value);
});

這兩種方法都避免了對非標準集合屬性的依賴,能在所有現代瀏覽器中正常運行。

總結

舊版 IE 提供了一些非標準的行為來簡化早期開發,但這些特性已被現代瀏覽器所移除。HTMLCollection.value 是其中之一,其行為主要依賴於集合內第一個元素的值。而現代瀏覽器更注重標準化,提供了更嚴謹的集合操作方式。

為了確保代碼的跨瀏覽器兼容性,我們應避免使用這些非標準特性,而是顯式地操作集合內的每個元素,這樣既能保證代碼的穩定性,也能提升其可讀性和可維護性。

 

完整代碼(IE和Chrome的輸出將會不同):

<!DOCTYPE html>
<html lang="zh-Hant">
<head>
  <meta charset="UTF-8">
  <title>表單元素同名賦值示例</title>
  <style>
    body {
      font-family: Arial, sans-serif;
      margin: 20px;
    }
    .input-group {
      margin-bottom: 10px;
    }
    .input-group label {
      display: inline-block;
      width: 100px;
    }
    #result {
      margin-top: 20px;
      padding: 10px;
      border: 1px solid #ccc;
      background-color: #f9f9f9;
    }
  </style>
</head>
<body>

  <h2>表單元素同名賦值示例</h2>

  <form id="myForm">
    <div class="input-group">
      <label for="input1">項目 1:</label>
      <input type="text" name="test" id="input1" value="初始值 1">
    </div>
    <div class="input-group">
      <label for="input2">項目 2:</label>
      <input type="text" name="test" id="input2" value="初始值 2">
    </div>
    <div class="input-group">
      <label for="input3">項目 3:</label>
      <input type="text" name="test" id="input3" value="初始值 3">
    </div>
    <button type="button" onclick="incorrectAssign()">錯誤的賦值方法</button>
  </form>


  <script>
    // 錯誤的賦值方法:只會影響第一個具有相同name的input
    function incorrectAssign() {
      
      //純正賦值方法,保證沒用 
      document.forms[0].test.value=1;
      console.log("執行: document.forms[0].test.value=1;");

      //帶變量的賦值方法
      var form = document.forms[0];
      console.log("執行: var form = document.forms[0];");
      form.test.value= '1';
      console.log("執行: form.test.value= '1';");

      console.log("輸出結果document.forms[0].test.value:"+document.forms[0].test.value);
      console.log("輸出結果form.test.value:"+form.test.value);
    }

  </script>

</body>
</html>

Chrome結果:

執行: document.forms[0].test.value=1;
Demo.html:57 執行: var form = document.forms[0];
Demo.html:59 執行: form.test.value= '1';
Demo.html:61 輸出結果document.forms[0].test.value:
Demo.html:62 輸出結果form.test.value:

IE結果:

執行: document.forms[0].test.value=1;
執行: var form = document.forms[0];
執行: form.test.value= '1';
輸出結果document.forms[0].test.value:1
輸出結果form.test.value:1

 

This article was last edited at 2025-01-24 15:16:55

Today's comments have reached the limit. If you want to comment, please wait until tomorrow (UTC-Time).

There is 16h20m28s left until you can comment.