datalist 数据列表
<datalist> 元素与 <input> 配合使用,为输入框提供预定义的建议列表。与 <select> 的强制选择不同,<datalist> 允许用户从建议中选择,也可以自由输入不在列表中的值。这种"建议 + 自由输入"的组合在搜索、地址输入等场景中非常实用。
前置知识
阅读本节前,建议先了解:select 下拉选择
基础概念
什么是 datalist
<datalist> 是一个包含一组 <option> 元素的容器,它本身不可见。通过 <input> 的 list 属性关联到 <datalist> 的 id,浏览器会在用户输入时显示匹配的建议列表。
<!-- datalist 定义建议 -->
<datalist id="browsers">
<option value="Chrome">
<option value="Firefox">
<option value="Safari">
<option value="Edge">
</datalist>
<!-- input 通过 list 属性关联 -->
<input type="text" list="browsers" placeholder="输入浏览器名称">datalist 与 select 对比
| 对比维度 | datalist | select |
|---|---|---|
| 输入方式 | 可以自由输入 + 选择建议 | 只能从列表中选择 |
| 可见性 | 输入时才显示 | 始终可见(或点击展开) |
| 筛选 | 根据输入自动过滤 | 无自动过滤 |
| 自定义输入 | 支持 | 不支持 |
| 表单提交 | 通过关联的 input 提交 | 直接提交 |
| 分组 | 不支持 optgroup | 支持 |
datalist 的核心特征
| 特征 | 说明 |
|---|---|
| 关联方式 | input 的 list 属性指向 datalist 的 id |
| 显示时机 | 用户聚焦或输入时 |
| 自动过滤 | 根据用户输入自动筛选匹配项 |
| 自由输入 | 用户可以输入列表之外的值 |
| 兼容性 | 所有现代浏览器支持,Safari 支持较晚(16.4+) |
语法
基本语法
<!-- 定义建议列表 -->
<datalist id="suggestionId">
<option value="值1">
<option value="值2">
<option value="值3" label="显示文本">
</datalist>
<!-- 关联到输入框 -->
<input type="text" list="suggestionId" name="field">option 的属性
| 属性 | 值 | 说明 |
|---|---|---|
value | 字符串 | 建议的值(选中后填入 input) |
label | 字符串 | 建议的显示文本(可选) |
disabled | 布尔属性 | 禁用该建议项(较少使用) |
详细说明
基本使用
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>datalist 基本使用</title>
<style>
.form-group {
margin-bottom: 20px;
}
label {
display: block;
font-weight: 500;
margin-bottom: 6px;
}
input {
padding: 10px 12px;
border: 1px solid #ccc;
border-radius: 6px;
font-size: 14px;
width: 300px;
}
</style>
</head>
<body>
<h2>编程语言搜索</h2>
<form action="/search" method="get">
<div class="form-group">
<label for="language">搜索编程语言:</label>
<!--
list="languages" 关联到 datalist 的 id
用户输入时,浏览器自动过滤匹配的语言
-->
<input type="text"
id="language"
name="q"
list="languages"
placeholder="输入语言名称...">
<!-- 建议列表 -->
<datalist id="languages">
<option value="JavaScript">
<option value="TypeScript">
<option value="Python">
<option value="Java">
<option value="C++">
<option value="C#">
<option value="Go">
<option value="Rust">
<option value="PHP">
<option value="Ruby">
<option value="Swift">
<option value="Kotlin">
</datalist>
</div>
<button type="submit">搜索</button>
</form>
<!--
用户行为示例:
1. 聚焦输入框 → 显示所有语言
2. 输入 "Ja" → 过滤显示 Java, JavaScript, Java (已删除)
3. 点击 "JavaScript" → 输入框填入 "JavaScript"
4. 也可以输入 "C" → 列表没有也行,自由输入
-->
</body>
</html>与不同 type 配合
<datalist> 可以与多种 <input> type 配合使用:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>datalist 与不同 type</title>
<style>
.demo {
margin-bottom: 20px;
padding: 16px;
border: 1px solid #e0e0e0;
border-radius: 8px;
}
label {
display: block;
font-weight: 500;
margin-bottom: 6px;
}
input, select {
padding: 8px;
border: 1px solid #ccc;
border-radius: 4px;
width: 300px;
}
</style>
</head>
<body>
<h2>datalist 与不同 input type</h2>
<!-- 与 text 配合 -->
<div class="demo">
<h3>text(城市输入)</h3>
<label for="city">城市:</label>
<input type="text" id="city" name="city" list="cityList" placeholder="输入或选择">
<datalist id="cityList">
<option value="北京">
<option value="上海">
<option value="广州">
<option value="深圳">
<option value="杭州">
<option value="成都">
</datalist>
</div>
<!-- 与 email 配合 -->
<div class="demo">
<h3>email(邮箱域名建议)</h3>
<label for="email">邮箱:</label>
<input type="email" id="email" name="email" list="domainList" placeholder="用户名@">
<datalist id="domainList">
<option value="@qq.com">
<option value="@163.com">
<option value="@126.com">
<option value="@gmail.com">
<option value="@outlook.com">
</datalist>
</div>
<!-- 与 url 配合 -->
<div class="demo">
<h3>url(网站建议)</h3>
<label for="website">网站:</label>
<input type="url" id="website" name="website" list="siteList" placeholder="https://">
<datalist id="siteList">
<option value="https://www.baidu.com">
<option value="https://www.google.com">
<option value="https://github.com">
<option value="https://stackoverflow.com">
</datalist>
</div>
<!-- 与 number 配合 -->
<div class="demo">
<h3>number(常用数量)</h3>
<label for="quantity">数量:</label>
<input type="number" id="quantity" name="quantity" list="qtyList" min="1">
<datalist id="qtyList">
<option value="1">
<option value="5">
<option value="10">
<option value="20">
<option value="50">
<option value="100">
</datalist>
</div>
<!-- 与 date 配合 -->
<div class="demo">
<h3>date(常用日期)</h3>
<label for="date">日期:</label>
<input type="date" id="date" name="date" list="dateList">
<datalist id="dateList">
<option value="2025-01-01">
<option value="2025-02-14">
<option value="2025-10-01">
<option value="2026-01-01">
</datalist>
</div>
</body>
</html>自定义输入 + 建议列表
<datalist> 最强大的特点是不完全限制用户的选择。用户可以选择建议,也可以自由输入。
<!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;
}
input {
width: 100%;
padding: 10px 12px;
border: 1px solid #ddd;
border-radius: 6px;
box-sizing: border-box;
font-size: 14px;
}
.comparison {
display: flex;
gap: 20px;
margin-top: 16px;
}
.comparison > div {
flex: 1;
padding: 16px;
border: 1px solid #e0e0e0;
border-radius: 8px;
}
.comparison h3 {
margin-top: 0;
font-size: 16px;
}
</style>
</head>
<body>
<h2>对比:datalist vs select</h2>
<div class="comparison">
<!-- datalist:可以选择建议,也可以自由输入 -->
<div>
<h3>datalist(自由输入 + 建议)</h3>
<label for="framework">框架:</label>
<input type="text" id="framework" name="framework" list="frameworks">
<datalist id="frameworks">
<option value="Vue.js">
<option value="React">
<option value="Angular">
<option value="Svelte">
</datalist>
<p style="font-size: 13px; color: #999; margin-top: 8px;">
可以选择 Vue.js,也可以输入 Solid.js
</p>
</div>
<!-- select:只能从列表中选择 -->
<div>
<h3>select(只能选择)</h3>
<label for="framework2">框架:</label>
<select id="framework2" name="framework2">
<option value="Vue.js">Vue.js</option>
<option value="React">React</option>
<option value="Angular">Angular</option>
<option value="Svelte">Svelte</option>
</select>
<p style="font-size: 13px; color: #999; margin-top: 8px;">
只能选择列表中的四个选项
</p>
</div>
</div>
</body>
</html>option 的 value 与 label
<datalist> 中的 <option> 支持 value 和 label 两个属性:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>option value 与 label</title>
</head>
<body>
<h2>datalist option 的 value 和 label</h2>
<form>
<label for="country">国家:</label>
<input type="text" id="country" name="country" list="countries">
<datalist id="countries">
<!--
value:选中后填入输入框的值
label:在下拉列表中额外显示的文本(某些浏览器)
注意:不同浏览器对 label 的显示方式不同
Chrome:显示 value
Firefox:显示 value (label)
-->
<option value="CN" label="中国">
<option value="US" label="美国">
<option value="JP" label="日本">
<option value="GB" label="英国">
</datalist>
</form>
<!--
用户体验:
- 列表中可能显示 "CN (中国)"
- 选中后输入框填入 "CN"
这在需要内部代码但显示友好名称时很有用
-->
</body>
</html>动态更新 datalist
<datalist> 的选项可以通过 JavaScript 动态添加、修改或删除:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>动态 datalist</title>
<style>
.form-group { margin-bottom: 16px; }
label { display: block; font-weight: 500; margin-bottom: 6px; }
input, button {
padding: 8px 12px;
border: 1px solid #ccc;
border-radius: 4px;
font-size: 14px;
}
input { width: 300px; }
button { cursor: pointer; }
</style>
</head>
<body>
<h2>动态建议列表</h2>
<form>
<div class="form-group">
<label for="tag">标签:</label>
<input type="text" id="tag" name="tag" list="tagList" placeholder="输入或选择标签">
<datalist id="tagList"></datalist>
</div>
</form>
<div style="margin-top: 16px;">
<label for="newTag">添加新标签:</label>
<input type="text" id="newTag" placeholder="输入新标签名称">
<button type="button" id="addBtn">添加</button>
</div>
<div id="tagCount" style="margin-top: 12px; color: #666;"></div>
<script>
const datalist = document.getElementById('tagList');
const newTagInput = document.getElementById('newTag');
const tagCount = document.getElementById('tagCount');
// 已有标签
const existingTags = ['JavaScript', 'HTML', 'CSS', 'Vue.js', 'React'];
// 初始化 datalist
function renderDatalist() {
datalist.innerHTML = '';
existingTags.forEach(tag => {
const option = document.createElement('option');
option.value = tag;
datalist.appendChild(option);
});
tagCount.textContent = `当前标签数:${existingTags.length}`;
}
// 添加新标签
document.getElementById('addBtn').addEventListener('click', function() {
const newTag = newTagInput.value.trim();
if (!newTag) return;
if (existingTags.includes(newTag)) {
alert('标签已存在');
return;
}
existingTags.push(newTag);
renderDatalist();
newTagInput.value = '';
});
// 初始化
renderDatalist();
</script>
</body>
</html>通过 AJAX 动态加载建议
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>AJAX datalist</title>
<style>
.search-box {
max-width: 500px;
margin: 40px auto;
}
input {
width: 100%;
padding: 12px 16px;
font-size: 16px;
border: 2px solid #ddd;
border-radius: 24px;
box-sizing: border-box;
}
input:focus {
outline: none;
border-color: #4a90d9;
}
</style>
</head>
<body>
<div class="search-box">
<h2>用户搜索</h2>
<!--
实际项目中,datalist 的选项通常来自服务器端搜索
由于 datalist 的原生过滤机制,可以直接更新 option
-->
<form action="/search" method="get">
<input type="text"
id="userSearch"
name="q"
list="userSuggestions"
placeholder="搜索用户名..."
autocomplete="off">
<datalist id="userSuggestions"></datalist>
</form>
</div>
<script>
const searchInput = document.getElementById('userSearch');
const datalist = document.getElementById('userSuggestions');
let debounceTimer = null;
searchInput.addEventListener('input', function() {
clearTimeout(debounceTimer);
const query = this.value.trim();
if (!query || query.length < 2) {
datalist.innerHTML = '';
return;
}
// 防抖 300ms
debounceTimer = setTimeout(async () => {
try {
// 模拟 AJAX 请求
// const response = await fetch(`/api/users?q=${encodeURIComponent(query)}`);
// const users = await response.json();
// 模拟数据
const users = [
{ id: 1, name: query + '_user1' },
{ id: 2, name: query + '_user2' },
{ id: 3, name: query + '_admin' },
];
// 更新 datalist
datalist.innerHTML = users.map(user =>
`<option value="${user.name}">`
).join('');
} catch (error) {
console.error('搜索失败', error);
}
}, 300);
});
</script>
</body>
</html>注意事项
Safari 的兼容性:Safari 从 16.4 版本开始支持
<datalist>。在旧版 Safari 中,<datalist>被忽略,输入框正常工作但没有建议功能。浏览器对建议列表的样式控制有限:不同浏览器对
<datalist>下拉列表的样式有差异,且 CSS 控制能力非常有限。datalist 不验证输入:用户可以选择列表外的值,
<datalist>不会限制或验证输入。大量选项的性能:如果 datalist 中有数百个选项,某些浏览器可能出现卡顿。建议限制在 100~200 个选项以内。
label 属性的浏览器差异:
<option>的label属性在不同浏览器中的显示方式不一致,Chrome 主要显示value,Firefox 可能显示value (label)。
最佳实践
需要自由输入 + 建议时用 datalist:如果用户可能输入不在预设列表中的值,使用 datalist 而非 select。
需要严格限制选项时用 select:如果用户只能从预设选项中选择,使用 select。
限制建议数量:不要在 datalist 中放置过多选项,影响性能和可读性。
配合 placeholder 引导:用 placeholder 提示用户可以自由输入。
Safari 兼容方案:对于需要兼容旧版 Safari 的场景,可以提供自定义的自动补全组件作为替代。
下一节
继续学习:optgroup 选项分组