Skip to content

select 下拉选择

<select> 元素创建一个下拉选择框,用户可以从预定义的选项列表中选择一个或多个值。与 radio 和 checkbox 不同,<select> 使用 <option> 子元素定义选项,在空间有限的场景中特别适合。本节将详细讲解单选和多选模式、<option><optgroup> 的使用、size 属性,以及 selected 默认选中。

前置知识

阅读本节前,建议先了解:checkbox 复选框

基础概念

什么是 select

<select> 是一个容器元素,内部包含 <option> 元素作为可选选项。点击 <select> 后弹出下拉列表,用户从中选择。

html
<!-- 基本 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 对比

对比维度selectradiocheckbox
空间占用小(一行高度)
可选项数量适合 5+ 选项适合 2~5 个适合 2~8 个
多选multiple 属性不支持支持
分组<optgroup><fieldset><fieldset>
搜索/过滤无(原生)

语法

基本语法

html
<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> 是单选的,显示为一个下拉列表。

html
<!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 + 点击选择连续范围。

html
<!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(显示为下拉列表形式)。

html
<!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> 中的可选项。

html
<!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 与文本

html
<!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> 用于将相关的选项分组,每个分组有一个标题。

html
<!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(不支持多级分组)
  • optgrouplabel 属性是分组标题,不可选
  • optgroup 可以设置 disabled 禁用整个分组
  • optgroup 不是 <option>,没有 value,不会随表单提交

JavaScript 操作 select

html
<!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>

实战示例

省市二级联动

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>

注意事项

  1. option 没有 value 时提交文本:省略 value 时,提交的值是 option 标签之间的文本内容。建议始终设置 value

  2. required 与空值选项:设置了 required 时,第一个 <option value=""> 可以作为占位。如果用户没有选择,验证失败。

  3. 多选的可用性问题<select multiple> 的原生交互(Ctrl/Cmd + 点击)对普通用户不友好,移动端体验更差。多选场景建议使用 checkbox。

  4. optgroup 不支持嵌套<optgroup> 内部只能放 <option>,不支持二级分组。

  5. optgroup 的 disabled 禁用整组:设置在 <optgroup> 上的 disabled 会禁用该组所有选项。

最佳实践

  1. 始终提供占位选项:第一个选项为 <option value="">请选择...</option>,配合 required 使用。

  2. 每个 option 设置有意义的 value:使用英文/拼音标识符而非中文作为 value。

  3. 选项不多时考虑 radio:如果选项只有 3~5 个,radio 的可操作性更好(所有选项一目了然)。

  4. 使用 optgroup 组织大量选项:当选项超过 7 个时,使用 <optgroup> 分组帮助用户快速定位。

  5. 动态 select 使用 JavaScript:联动下拉框、动态加载选项等场景,使用 JavaScript 操作 DOM。

下一节

继续学习:datalist 数据列表

参考链接