IE9 獨有的 Bug:`
現象復現
<select id="city">
<option value="bj">北京</option>
<option value="sh">上海</option>
<option value="gz">廣州</option>
</select>
用戶未操作,頁面加載完成:
- Chrome/FF/IE10+:`$('#city').find('option:selected').val()` → `"bj"`(第一項被瀏覽器自動視為選中)。
- IE 9.0.8112.16421:同樣代碼 → `undefined`。
根因分析
- HTML 標準:`
- IE9 實現缺陷:未在 DOM 屬性上同步 `selectedIndex=0`,導致 jQuery 的 Sizzle 選擇器 `:selected` 匹配失敗(它依賴 `option.selected === true`)。
- jQuery 版本:1.x/2.x/3.x 均受影響,因底層均用原生 `querySelectorAll` 或屬性遍歷。
三種兼容修復方案
方案一:原生 DOM `selectedIndex`(推薦,零依賴、最快)
var sel = document.getElementById('city');
var val = sel.options[sel.selectedIndex].value; // IE9 正常返回 "bj"
- 直接讀取瀏覽器維護的 `selectedIndex`,繞過 jQuery 選擇器。
- 所有瀏覽器一致,性能最優。
方案二:jQuery `val()` 直接取值(簡潔,內部已修正)
var val = $('#city').val(); // jQuery 內部用 selectedIndex 邏輯,IE9 正常
- jQuery 1.6+ `val()` 針對 `
- 代碼最少,遷移成本最低。
方案三:HTML 端補全 `selected` 屬性(源頭治理)
<select id="city">
<option value="bj" selected>北京</option> <!-- 顯式聲明 -->
<option value="sh">上海</option>
<option value="gz">廣州</option>
</select>
- 讓所有瀏覽器(含 IE9)在 DOM 屬性層面就有 `selected=true`。
- 後端模板渲染時直接輸出,一勞永逸。
方案對比與選型建議
| 方案 | 修改範圍 | 相容性 | 性能 | 推薦指數 |
| 原生 selectedIndex | JS 取值處 | 完美 | ★★★★★ | ★★★★★ |
| jQuery val() | JS 取值處 | 完美 (jQ 1.6+) | ★★★★☆ | ★★★★☆ |
| HTML 顯式 selected | 模板/後端 | 完美 | ★★★★★ | ★★★★★ (新項目) |
最佳實踐棧
- 新項目:模板渲染 `
- 存量項目:全局封裝 `function getSelectVal(id) { return document.getElementById(id).options[document.getElementById(id).selectedIndex].value; }` 替換所有 `:selected` 用法。
- 單元測試:在 IE9 VM 中跑 `select` 取值用例,納入 CI。
- 棄用 `:selected`:代碼審查規則禁止在 `
延伸:IE9 其他表單兼容性坑
IE9 雖已退役,但企業內網、舊系統仍存量巨大。**「特性檢測優於瀏覽器檢測,原生 API 優於庫封裝」** 是應對此類兼容性問題的黃金法則。