select 下拉选择
<select> 元素创建一个下拉选择框,用户可以从预定义的选项列表中选择一个或多个值。与 radio 和 checkbox 不同,<select> 使用 <option> 子元素定义选项,在空间有限的场景中特别适合。本节将详细讲解单选和多选模式、<option> 和 <optgroup> 的使用、size 属性,以及 selected 默认选中。
前置知识
阅读本节前,建议先了解:checkbox 复选框
基础概念
什么是 select
<select> 是一个容器元素,内部包含 <option> 元素作为可选选项。点击 <select> 后弹出下拉列表,用户从中选择。
<!-- 基本 select -->
<select name="city">
<option value="">请选择城市</option>
<option value="beijing">北京</option>
<option value="shanghai">上海</option>
<option value="guangzhou">广州</option>
</select>select 的核心特征
| 特征 | 说明 |
|---|---|
| 选项来源 | <option> 子元素 |
| 默认模式 | 单选(下拉列表) |
| 多选模式 | 添加 multiple 属性 |
| 空值选项 | 需要 <option value=""> 占位 |
| 分组 | 使用 <optgroup> |
select 与 radio/checkbox 对比
| 对比维度 | select | radio | checkbox |
|---|---|---|---|
| 空间占用 | 小(一行高度) | 中 | 中 |
| 可选项数量 | 适合 5+ 选项 | 适合 2~5 个 | 适合 2~8 个 |
| 多选 | multiple 属性 | 不支持 | 支持 |
| 分组 | <optgroup> | <fieldset> | <fieldset> |
| 搜索/过滤 | 无(原生) | 无 | 无 |
语法
基本语法
<select
name="字段名"
id="唯一标识"
size="可见行数"
multiple
required
disabled
>
<option value="值1" selected>显示文本1</option>
<option value="值2">显示文本2</option>
<option value="值3" disabled>不可选</option>
<optgroup label="分组标题">
<option value="值4">显示文本4</option>
</optgroup>
</select>属性说明
| 属性 | 值 | 说明 |
|---|---|---|
name | 字符串 | 提交数据的键名 |
id | 字符串 | 唯一标识 |
size | 正整数 | 可见选项行数(默认 1) |
multiple | 布尔属性 | 启用多选模式 |
required | 布尔属性 | 必须选择一项 |
disabled | 布尔属性 | 禁用整个 select |
form | 字符串 | 关联外部表单 |
option 属性
| 属性 | 值 | 说明 |
|---|---|---|
value | 字符串 | 选中时提交的值 |
selected | 布尔属性 | 默认选中 |
disabled | 布尔属性 | 禁用该选项 |
label | 字符串 | 选项的简短标签 |
详细说明
单选模式(默认)
默认情况下,<select> 是单选的,显示为一个下拉列表。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>select 单选</title>
<style>
.form-group {
margin-bottom: 20px;
}
label {
display: block;
font-weight: 500;
margin-bottom: 6px;
}
select {
padding: 10px 12px;
border: 1px solid #ccc;
border-radius: 6px;
font-size: 14px;
min-width: 200px;
}
</style>
</head>
<body>
<h2>用户注册</h2>
<form action="/register" method="post">
<div class="form-group">
<label for="province">省份</label>
<select id="province" name="province" required>
<!-- 占位选项,value 为空 -->
<option value="">请选择省份</option>
<option value="beijing">北京</option>
<option value="shanghai">上海</option>
<option value="guangdong">广东</option>
<option value="zhejiang">浙江</option>
<option value="jiangsu">江苏</option>
</select>
</div>
<div class="form-group">
<label for="education">学历</label>
<select id="education" name="education">
<option value="high-school">高中</option>
<option value="college">大专</option>
<option value="bachelor" selected>本科</option>
<option value="master">硕士</option>
<option value="phd">博士</option>
</select>
<!-- 默认选中"本科" -->
</div>
<button type="submit">注册</button>
</form>
</body>
</html>空值占位选项
使用 <option value="">请选择...</option> 作为第一项,提示用户进行选择。设置 required 后,如果用户没有选择有效选项(仍停留在空值项),表单无法提交。
多选模式(multiple)
添加 multiple 属性后,<select> 变为多选模式。用户可以通过 Ctrl(Windows)/ Cmd(Mac)+ 点击选择多个选项,或 Shift + 点击选择连续范围。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>select multiple 多选</title>
<style>
.form-group {
margin-bottom: 20px;
}
label {
display: block;
font-weight: 500;
margin-bottom: 6px;
}
select {
padding: 8px;
border: 1px solid #ccc;
border-radius: 6px;
font-size: 14px;
}
.hint {
font-size: 13px;
color: #999;
margin-top: 4px;
}
</style>
</head>
<body>
<h2>技能选择</h2>
<form action="/profile" method="post">
<div class="form-group">
<label for="skills">选择你的技能(可多选):</label>
<!--
multiple:启用多选
size="6":显示6行,同时看到多个选项
不设 size 时,多选模式默认显示的行数因浏览器而异
-->
<select id="skills" name="skills" multiple size="6" required>
<option value="html">HTML</option>
<option value="css">CSS</option>
<option value="javascript">JavaScript</option>
<option value="typescript">TypeScript</option>
<option value="python">Python</option>
<option value="java">Java</option>
<option value="go">Go</option>
<option value="rust">Rust</option>
</select>
<p class="hint">按住 Ctrl(Mac 上为 Cmd)点击可多选</p>
</div>
<button type="submit">提交</button>
</form>
<!--
假设用户选中了 HTML、CSS、JavaScript
提交的数据:
skills=html&skills=css&skills=javascript
与多选 checkbox 的提交格式相同
-->
</body>
</html>多选模式的可用性问题
<select multiple> 的原生多选交互不太友好(需要按住 Ctrl/Cmd),很多用户不了解这个操作。在移动端,体验更差。如果需要多选,建议使用 checkbox 或第三方多选组件。
size 可见行数
size 属性控制 <select> 同时显示的选项行数。默认值是 1(显示为下拉列表形式)。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>size 属性</title>
</head>
<body>
<h2>size 不同值的效果</h2>
<!-- size=1:默认下拉列表 -->
<h3>size="1"(默认下拉)</h3>
<select name="s1" size="1">
<option>选项一</option>
<option>选项二</option>
<option>选项三</option>
<option>选项四</option>
<option>选项五</option>
</select>
<!-- size=3:显示3行 -->
<h3>size="3"(列表框)</h3>
<select name="s3" size="3">
<option>选项一</option>
<option>选项二</option>
<option>选项三</option>
<option>选项四</option>
<option>选项五</option>
</select>
<!-- size=全部:显示所有选项 -->
<h3>size="5"(全部可见)</h3>
<select name="s5" size="5">
<option>选项一</option>
<option>选项二</option>
<option>选项三</option>
<option>选项四</option>
<option>选项五</option>
</select>
</body>
</html>option 元素
<option> 定义 <select> 中的可选项。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>option 详解</title>
</head>
<body>
<h2>option 属性</h2>
<form action="/order" method="post">
<label for="size">尺码:</label>
<select id="size" name="size">
<!-- value:提交的值 -->
<!-- selected:默认选中 -->
<!-- disabled:不可选(灰色显示) -->
<option value="xs">XS 加小号</option>
<option value="s">S 小号</option>
<option value="m" selected>M 中号</option>
<option value="l">L 大号</option>
<option value="xl">XL 加大号</option>
<option value="xxl" disabled>XXL 已售罄</option>
</select>
<br><br>
<!--
option 的文本内容可以是 option 标签之间的内容
也可以用 label 属性指定(较少使用)
-->
<label for="color">颜色:</label>
<select id="color" name="color">
<option value="red" label="红色">红色 (#FF0000)</option>
<option value="blue" label="蓝色">蓝色 (#0000FF)</option>
<option value="green" label="绿色">绿色 (#00FF00)</option>
<!-- label 属性在 select 下拉中作为显示文本(某些浏览器) -->
</select>
<button type="submit">提交</button>
</form>
</body>
</html>option 的 value 与文本
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>value 与文本</title>
</head>
<body>
<h2>option 的 value 和显示文本</h2>
<form action="/submit" method="post">
<select name="country">
<!-- value 是提交给服务器的值 -->
<!-- 标签之间的内容是用户看到的文本 -->
<option value="CN">中国</option>
<option value="US">美国</option>
<option value="JP">日本</option>
<option value="KR">韩国</option>
</select>
<!--
如果省略 value,提交的值就是 option 的文本内容
-->
<select name="city">
<option>北京</option> <!-- 提交 city=北京 -->
<option>上海</option> <!-- 提交 city=上海 -->
</select>
<!--
最佳实践:始终设置 value
因为文本可能包含中文、空格等,不适合作为程序标识符
-->
</form>
</body>
</html>optgroup 选项分组
<optgroup> 用于将相关的选项分组,每个分组有一个标题。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>optgroup 分组</title>
</head>
<body>
<h2>select 中的 optgroup</h2>
<form action="/search" method="get">
<label for="category">选择分类:</label>
<select id="category" name="category">
<option value="">全部分类</option>
<!-- optgroup 分组 -->
<optgroup label="前端开发">
<option value="html">HTML</option>
<option value="css">CSS</option>
<option value="javascript">JavaScript</option>
<option value="vue">Vue.js</option>
<option value="react">React</option>
</optgroup>
<optgroup label="后端开发">
<option value="nodejs">Node.js</option>
<option value="python">Python</option>
<option value="java">Java</option>
<option value="go">Go</option>
</optgroup>
<optgroup label="数据库" disabled>
<option value="mysql" disabled>MySQL</option>
<option value="mongodb" disabled>MongoDB</option>
</optgroup>
</select>
<button type="submit">搜索</button>
</form>
</body>
</html>optgroup 注意事项
optgroup只能嵌套<option>,不能嵌套其他optgroup(不支持多级分组)optgroup的label属性是分组标题,不可选optgroup可以设置disabled禁用整个分组optgroup不是<option>,没有value,不会随表单提交
JavaScript 操作 select
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>JS 操作 select</title>
</head>
<body>
<h2>JavaScript 操作 select</h2>
<form id="myForm">
<label for="city">城市:</label>
<select id="city" name="city">
<option value="beijing">北京</option>
<option value="shanghai">上海</option>
<option value="guangzhou">广州</option>
<option value="shenzhen">深圳</option>
</select>
</form>
<div style="margin-top: 16px;">
<button type="button" id="btnGetValue">获取选中值</button>
<button type="button" id="btnGetText">获取选中文本</button>
<button type="button" id="btnSetValue">设置为深圳</button>
<button type="button" id="btnAddOption">添加杭州</button>
</div>
<div id="output" style="margin-top: 12px; padding: 12px; background: #f5f5f5;"></div>
<script>
const select = document.getElementById('city');
const output = document.getElementById('output');
// 监听变化
select.addEventListener('change', function() {
output.textContent = `选中值:${this.value},文本:${this.options[this.selectedIndex].text}`;
});
// 获取选中值
document.getElementById('btnGetValue').addEventListener('click', () => {
output.textContent = '选中值:' + select.value;
});
// 获取选中文本
document.getElementById('btnGetText').addEventListener('click', () => {
const text = select.options[select.selectedIndex].text;
output.textContent = '选中文本:' + text;
});
// 编程方式设置选中
document.getElementById('btnSetValue').addEventListener('click', () => {
select.value = 'shenzhen';
// 或者通过 selectedIndex
// select.selectedIndex = 3;
});
// 动态添加选项
document.getElementById('btnAddOption').addEventListener('click', () => {
const option = document.createElement('option');
option.value = 'hangzhou';
option.text = '杭州';
select.add(option);
});
</script>
</body>
</html>实战示例
省市二级联动
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>省市联动</title>
<style>
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
max-width: 500px;
margin: 40px auto;
padding: 20px;
}
.form-group {
margin-bottom: 20px;
}
label {
display: block;
font-weight: 500;
margin-bottom: 6px;
}
select {
width: 100%;
padding: 10px 12px;
border: 1px solid #ddd;
border-radius: 6px;
font-size: 14px;
box-sizing: border-box;
}
</style>
</head>
<body>
<h2>地址选择</h2>
<form action="/address" method="post">
<div class="form-group">
<label for="province">省份</label>
<select id="province" name="province" required>
<option value="">请选择省份</option>
</select>
</div>
<div class="form-group">
<label for="city">城市</label>
<select id="city" name="city" required disabled>
<option value="">请先选择省份</option>
</select>
</div>
<button type="submit">提交</button>
</form>
<script>
// 省市数据
const data = {
'北京': ['东城区', '西城区', '朝阳区', '海淀区', '丰台区'],
'上海': ['黄浦区', '徐汇区', '长宁区', '静安区', '浦东新区'],
'广东': ['广州', '深圳', '珠海', '东莞', '佛山'],
'浙江': ['杭州', '宁波', '温州', '嘉兴', '绍兴'],
'江苏': ['南京', '苏州', '无锡', '常州', '南通']
};
const provinceSelect = document.getElementById('province');
const citySelect = document.getElementById('city');
// 填充省份
Object.keys(data).forEach(province => {
const option = document.createElement('option');
option.value = province;
option.text = province;
provinceSelect.appendChild(option);
});
// 省份变化时更新城市
provinceSelect.addEventListener('change', function() {
const province = this.value;
// 清空城市下拉框
citySelect.innerHTML = '';
if (province && data[province]) {
// 启用城市下拉框
citySelect.disabled = false;
// 添加默认选项
const defaultOption = document.createElement('option');
defaultOption.value = '';
defaultOption.text = '请选择城市';
citySelect.appendChild(defaultOption);
// 添加城市选项
data[province].forEach(city => {
const option = document.createElement('option');
option.value = city;
option.text = city;
citySelect.appendChild(option);
});
} else {
citySelect.disabled = true;
const defaultOption = document.createElement('option');
defaultOption.value = '';
defaultOption.text = '请先选择省份';
citySelect.appendChild(defaultOption);
}
});
</script>
</body>
</html>注意事项
option 没有 value 时提交文本:省略
value时,提交的值是 option 标签之间的文本内容。建议始终设置value。required 与空值选项:设置了
required时,第一个<option value="">可以作为占位。如果用户没有选择,验证失败。多选的可用性问题:
<select multiple>的原生交互(Ctrl/Cmd + 点击)对普通用户不友好,移动端体验更差。多选场景建议使用 checkbox。optgroup 不支持嵌套:
<optgroup>内部只能放<option>,不支持二级分组。optgroup 的 disabled 禁用整组:设置在
<optgroup>上的disabled会禁用该组所有选项。
最佳实践
始终提供占位选项:第一个选项为
<option value="">请选择...</option>,配合required使用。每个 option 设置有意义的 value:使用英文/拼音标识符而非中文作为 value。
选项不多时考虑 radio:如果选项只有 3~5 个,radio 的可操作性更好(所有选项一目了然)。
使用 optgroup 组织大量选项:当选项超过 7 个时,使用
<optgroup>分组帮助用户快速定位。动态 select 使用 JavaScript:联动下拉框、动态加载选项等场景,使用 JavaScript 操作 DOM。
下一节
继续学习:datalist 数据列表