选择框是通过 <select> 和 <option> 元素创建的。它常用于在有限选项里挑选值、做条件过滤或配置参数。为了方便与这个控件交互,除了所有表单字段共有的属性和方法外,HTMLSelectElement 类型还提供下列属性和方法。
设计数据结构时,通常会将 value 作为提交给后端的稳定标识,text 为对用户友好的展示文案,两者应保持同步更新。
| 成员 | 类型/返回值 | 说明 |
|---|---|---|
add(option, rel) | 方法 | 在参考项 rel 之前插入新 <option>;传入 null/undefined 时追加到末尾 |
length | 数字 | 选项数量,可读写 |
multiple | 布尔值 | 是否允许多选,对应 HTML 的 multiple 属性 |
options | HTMLOptionsCollection | 所有 <option> 的集合,可通过索引或名称访问 |
remove(index) | 方法 | 移除指定位置的选项 |
selectedIndex | 数字 | 第一个被选中的选项下标,无选中项时为 -1 |
selectedOptions | HTMLCollection | 只读集合,包含当前所有选中的 <option>(多选时尤其方便) |
size | 数字 | 可见的行数,对应 HTML 的 size 属性 |
type | 字符串 | select-one 或 select-multiple |
value | 字符串 | 当前选中项的值,等价于 HTML 中的 value 属性 |
选择框的 value 属性由当前选中项决定,相应规则如下:
<option> 提供了 value 属性,则直接返回该值(即使值为空字符串)value 属性,则返回该选项的文本内容value 仍然只返回“第一个选中的值”,可通过 selectedOptions 获取全部以下面的选择框为例:
<select name="location" id="selLocation">
<option value="Sunnyvale, CA">Sunnyvale</option>
<option value="Los Angeles, CA">Los Angeles</option>
<option value="Mountain View, CA">Mountain View</option>
<option value="">China</option>
<option>Australia</option>
</select>要一次性取出所有被选中的值,可以利用 selectedOptions:
const selectbox = document.getElementById("selLocation")
const values = Array.from(selectbox.selectedOptions, (option) => option.value)
console.log(values)在 DOM 中每个 <option> 元素都有个 HTMLOptionElement 对象表示。为便于访问数据,该对象提供如下常用属性:
| 属性 | 类型 | 说明 |
|---|---|---|
index | 数字 | 当前选项在 options 集合中的索引 |
label | 字符串 | 显示在 UI 上的标签文本,等价于 label 属性 |
selected | 布尔值 | 是否被选中,设置为 true 会选中该选项 |
text | 字符串 | 选项的可见文本 |
value | 字符串 | 选项的值,等价于 value 属性 |
disabled | 布尔值 | 是否禁用该选项 |
form | HTMLFormElement | 指向所属的 <form> 元素(若存在) |
虽然可以使用常规的 DOM 功能来访问这些信息,但效率较低:
const selectbox = document.forms[0].elements["location"]
// 不推荐
const text1 = selectbox.options[0].firstChild.nodeValue // 获取第一项的文本
const value1 = selectbox.options[0].getAttribute("value") // 获取第一项的值
// 推荐
const text2 = selectbox.options[0].text // 选项文本
const value2 = selectbox.options[0].value // 选项值const selectEl = document.getElementById("selLocation")
selectEl.addEventListener("change", (event) => {
console.log("选项变更", event.target.value)
})
selectEl.addEventListener("input", (event) => {
// 某些浏览器会同步触发 input,必要时做防抖/节流
console.log("输入事件", event.target.value)
})change 在选择项确定后立即触发,不需要等待 blurchange 更稳妥;input 可作为补充选择框同样会触发 focus、blur,可用于给出操作提示或执行校验:
const helper = document.getElementById("selectHelp")
selectEl.addEventListener("focus", () => {
helper.textContent = "使用上下键或输入首字母可以快速选中"
})
selectEl.addEventListener("blur", () => {
helper.textContent = ""
})搭配 aria-describedby 可以让读屏软件感知提示内容。
const countrySelect = document.getElementById("country")
const citySelect = document.getElementById("city")
const cityMap = {
China: ["Beijing", "Shanghai", "Shenzhen"],
USA: ["Sunnyvale", "Los Angeles", "Austin"]
}
countrySelect.addEventListener("change", () => {
const cities = cityMap[countrySelect.value] ?? []
citySelect.options.length = 0
for (const city of cities) {
citySelect.add(new Option(city, city))
}
citySelect.disabled = cities.length === 0
})根据需要可以在末尾设置 citySelect.selectedIndex = 0 并手动触发 change,确保联动后的默认值同步。
对于单选框,访问选中项的最简单方式,就是使用选择框的 selectedIndex 属性:
const selectEl = document.getElementById("selLocation")
const selectedIndex = selectEl.selectedIndex
if (selectedIndex === -1) {
console.log("Nothing selected")
} else {
const selectedOption = selectEl.options[selectedIndex]
console.log(`Selected index: ${selectedIndex}`)
console.log(`Selected text: ${selectedOption.text}`)
console.log(`Selected value: ${selectedOption.value}`)
}对于多选框,获取 selectedIndex 属性返回选中的第一项的索引。但设置 selectedIndex 会取消其他所有选项的选中状态,只选中指定的那一项。
通过取得选项的引用并将其 selected 属性设置为 true 来设置选中:
selectbox.options[0].selected = true⚠️ 与
selectedIndex不同,在多选框中设置选项的selected属性,不会取消对其他选中项的选择,因而可以动态选中任意多个项。但在单选选择框中,修改某个选项的selected属性则会取消对其他选项的选择。 注意:将selected属性设置为false对单选选择框没有影响 实际上selected属性的作用主要是,确定用户选择了哪一项。要取得所有选中的项,可以循环遍历选项集合并判断selected属性:
function getSelectedOptions(selectEl) {
const result = []
for (const option of selectEl.options) {
if (option.selected) {
result.push(option)
}
}
return result
}
const selectEl = document.getElementById("selLocation")
const selectedOptions = getSelectedOptions(selectEl)
let message = ""
for (const option of selectedOptions) {
message += `Selected index: ${option.index}\n`
message += `Selected text: ${option.text}\n`
message += `Selected value: ${option.value}\n`
}
console.log(message)
// 若只需值数组,可直接映射
const values = selectedOptions.map((option) => option.value)可以使用 JavaScript 动态创建选项,并将它们添加到选择框:
Option 构造函数add 方法const selectbox = document.getElementById("selLocation")
// 1. DOM 创建
const option1 = document.createElement("option")
option1.value = "Option value"
option1.textContent = "Option text"
selectbox.append(option1)
// 2. 构造函数
const option2 = new Option("Option text", "Option value")
selectbox.append(option2)
// 3. add 方法(第二个参数为参考节点,可传 null/undefined 追加到末尾)
const option3 = new Option("Inserted before first", "before")
selectbox.add(option3, selectbox.options[0] ?? null)append/appendChild 适合批量插入,可先构建 DocumentFragment 后统一追加Option 构造函数语法简洁,但不便携带自定义属性add 支持指定插入位置,API 与旧规范兼容如果想将新选项插入列表中间,可以配合 insertBefore 或给 add 传入参考项。
移除选项的方式有很多种:
removeChild:传入要移除的选项节点remove(index) 方法selectbox.options.length = 0 或 selectbox.innerHTML = ""(注意:后者会重建 DOM,可能丢失事件监听)const selectbox = document.getElementById("selLocation")
// 方式一:removeChild
selectbox.removeChild(selectbox.options[0])
// 方式二:remove(index)(与方式一选其一,两者都执行会移除两项)
// selectbox.remove(0)
// 清空所有选项
while (selectbox.options.length > 0) {
selectbox.remove(0)
}
// 或者更简洁:
selectbox.options.length = 0使用 appendChild 可以将一个选择框中的选项直接移动到另一个选择框:
const selectbox1 = document.getElementById("selLocations1")
const selectbox2 = document.getElementById("selLocations2")
// 将所有选中项移动到目标选择框
for (const option of Array.from(selectbox1.selectedOptions)) {
selectbox2.appendChild(option)
}重排选项次序最好的方式是使用 insertBefore 或 add 的第二个参数:
const selectbox = document.getElementById("selLocation")
// 将索引为 2 的选项移动到索引为 0 的位置
const optionToMove = selectbox.options[2]
// 方式一:insertBefore
selectbox.insertBefore(optionToMove, selectbox.options[0])
// 方式二:add(与方式一选其一,勿对同一节点连续执行)
// selectbox.add(optionToMove, selectbox.options[0])使用 new FormData(form) 可以一次性读取表单中所有选择框的值,多选字段会返回多条记录:
const form = document.querySelector("form")
form.addEventListener("submit", (event) => {
event.preventDefault()
const data = new FormData(form)
console.log(data.get("location"))
console.log(data.getAll("hobbies")) // 针对多选
})选择框同样支持原生的约束校验(如 required)。可以通过 selectbox.setCustomValidity() 自定义错误消息
添加 <label for="selectId"> 可以显著提升无障碍体验,多选时可额外提供帮助文本说明如何选择多项(例如提示使用 Ctrl/Cmd)
在批量更新大量选项时,避免逐项插入造成的反复重排或闪烁:
function populateSelect(selectEl, items) {
const fragment = document.createDocumentFragment()
for (const item of items) {
const option = new Option(item.label, item.value)
fragment.append(option)
}
selectEl.replaceChildren(fragment)
}DocumentFragment 可显著降低插入成本;旧浏览器可退化为 appendChildreplaceChildren 会一次性替换内容,必要时事先缓存旧选中值再恢复innerHTML = "" 更高效且不会执行字符串解析加载远程数据的常见模式:
async function fetchOptions(url, selectEl, { placeholder } = {}) {
selectEl.disabled = true
selectEl.options.length = 0
if (placeholder) {
selectEl.add(new Option(placeholder, ""))
}
try {
const response = await fetch(url)
const data = await response.json()
for (const { label, value } of data) {
selectEl.add(new Option(label, value))
}
} catch (error) {
console.error("加载选项失败", error)
selectEl.setCustomValidity("暂时无法加载选项,请稍后再试")
} finally {
selectEl.disabled = false
}
}加载过程中可设置 aria-busy="true" 或展示骨架屏,避免用户误以为控件不可用。
<select> 提供语义化的 <label>,必要时通过 aria-describedby 关联提示文本value 属性会导致提交到后端的是文本内容,后续改文案可能破坏数据selectEl.value 只返回第一个值,应遍历 selectedOptions<option> 后 selectedIndex 不会自动指向新选项,需要时手动设置value,会让 UI 与状态不同步