在掌握了表单基础后,我们需要学习更多高级特性,包括表单控件、验证API、数据提交等。
东巴文(db-w.cn) 认为:高级表单技术能够创建更强大、更友好的用户交互界面。
<!-- 日期选择器 -->
<input type="date" name="birthday">
<!-- 时间选择器 -->
<input type="time" name="appointment">
<!-- 日期时间选择器 -->
<input type="datetime-local" name="meeting">
<!-- 月份选择器 -->
<input type="month" name="month">
<!-- 周选择器 -->
<input type="week" name="week">
东巴文日期时间类型对比:
| 类型 | 格式 | 示例值 | 说明 |
|---|---|---|---|
date |
YYYY-MM-DD | 2024-01-15 | 日期 |
time |
HH:MM | 14:30 | 时间 |
datetime-local |
YYYY-MM-DDTHH:MM | 2024-01-15T14:30 | 日期时间 |
month |
YYYY-MM | 2024-01 | 月份 |
week |
YYYY-Www | 2024-W03 | 周 |
<!-- 数字输入 -->
<input type="number" name="quantity" min="1" max="100" step="1" value="1">
<!-- 范围滑块 -->
<input type="range" name="volume" min="0" max="100" step="10" value="50">
<output for="volume" id="volume-output">50</output>
<script>
const range = document.querySelector('input[name="volume"]');
const output = document.getElementById('volume-output');
range.addEventListener('input', function() {
output.textContent = this.value;
});
</script>
东巴文数字属性:
| 属性 | 说明 | 示例 |
|---|---|---|
min |
最小值 | min="0" |
max |
最大值 | max="100" |
step |
步长 | step="0.1" |
value |
默认值 | value="50" |
<input type="color" name="color" value="#ff0000">
<output for="color" id="color-output">#ff0000</output>
<script>
const colorInput = document.querySelector('input[name="color"]');
const colorOutput = document.getElementById('color-output');
colorInput.addEventListener('input', function() {
colorOutput.textContent = this.value;
});
</script>
<!-- 搜索框 -->
<input type="search" name="q" placeholder="搜索..." results="5" autosave="search-history">
<!-- 带建议的搜索框 -->
<input type="search" name="q" list="search-suggestions" placeholder="搜索课程...">
<datalist id="search-suggestions">
<option value="HTML基础">
<option value="CSS样式">
<option value="JavaScript入门">
<option value="Python编程">
</datalist>
<datalist>元素<datalist>元素为输入框提供预定义选项:
<input type="text" name="browser" list="browsers" placeholder="选择浏览器">
<datalist id="browsers">
<option value="Chrome">
<option value="Firefox">
<option value="Safari">
<option value="Edge">
<option value="Opera">
</datalist>
东巴文说明:
<datalist>提供自动完成建议<select>不同,不限制输入<datalist>与<select>对比东巴文对比表格:
| 特性 | <datalist> |
<select> |
|---|---|---|
| 输入方式 | 可输入+选择 | 只能选择 |
| 自定义值 | ✅ 允许 | ❌ 不允许 |
| 搜索功能 | ✅ 支持 | ❌ 不支持 |
| 移动端体验 | 较好 | 很好 |
| 适用场景 | 搜索、建议 | 固定选项 |
<output>元素<output>元素用于显示计算结果:
<form oninput="result.value = parseInt(a.value) + parseInt(b.value)">
<input type="number" name="a" value="0"> +
<input type="number" name="b" value="0"> =
<output name="result">0</output>
</form>
东巴文output属性:
| 属性 | 说明 | 示例 |
|---|---|---|
for |
关联元素ID | for="a b" |
name |
名称 | name="result" |
form |
所属表单 | form="myForm" |
<progress>和<meter>元素<progress>元素显示任务完成进度:
<!-- 不确定进度 -->
<progress>加载中...</progress>
<!-- 确定进度 -->
<progress value="70" max="100">70%</progress>
<!-- JavaScript控制 -->
<progress id="download-progress" value="0" max="100"></progress>
<button onclick="startDownload()">开始下载</button>
<script>
function startDownload() {
const progress = document.getElementById('download-progress');
let value = 0;
const interval = setInterval(() => {
value += 10;
progress.value = value;
if (value >= 100) {
clearInterval(interval);
alert('下载完成!');
}
}, 500);
}
</script>
<meter>元素显示已知范围内的标量测量值:
<!-- 磁盘使用量 -->
<meter value="0.7" min="0" max="1">70%</meter>
<!-- 考试分数 -->
<meter value="85" min="0" max="100" low="60" high="90" optimum="100">
85分
</meter>
<!-- 温度 -->
<meter value="25" min="0" max="40" low="10" high="30" optimum="20">
25°C
</meter>
东巴文meter属性:
| 属性 | 说明 | 示例 |
|---|---|---|
value |
当前值 | value="70" |
min |
最小值 | min="0" |
max |
最大值 | max="100" |
low |
低值区域 | low="30" |
high |
高值区域 | high="70" |
optimum |
最优值 | optimum="50" |
东巴文说明:
<progress>:用于任务进度(动态)<meter>:用于静态测量值东巴文验证API属性:
| 属性/方法 | 说明 | 返回值 |
|---|---|---|
checkValidity() |
检查有效性 | boolean |
reportValidity() |
检查并报告 | boolean |
setCustomValidity(msg) |
设置自定义消息 | void |
validationMessage |
验证消息 | string |
validity |
有效性状态对象 | ValidityState |
willValidate |
是否会验证 | boolean |
东巴文ValidityState属性:
| 属性 | 说明 | 示例场景 |
|---|---|---|
valueMissing |
值缺失 | required字段为空 |
typeMismatch |
类型不匹配 | email格式错误 |
patternMismatch |
模式不匹配 | pattern验证失败 |
tooLong |
超出最大长度 | 超过maxlength |
tooShort |
小于最小长度 | 小于minlength |
rangeUnderflow |
小于最小值 | 小于min |
rangeOverflow |
大于最大值 | 大于max |
stepMismatch |
步长不匹配 | 不符合step |
customError |
自定义错误 | setCustomValidity设置 |
valid |
是否有效 | 所有验证通过 |
<form id="myForm">
<input type="email" id="email" name="email" required>
<span id="email-error" class="error"></span>
<input type="password" id="password" name="password"
minlength="6" required>
<span id="password-error" class="error"></span>
<button type="submit">提交</button>
</form>
<script>
const form = document.getElementById('myForm');
const email = document.getElementById('email');
const password = document.getElementById('password');
// 实时验证
email.addEventListener('input', function() {
validateEmail();
});
password.addEventListener('input', function() {
validatePassword();
});
function validateEmail() {
const error = document.getElementById('email-error');
if (email.validity.valueMissing) {
error.textContent = '请输入邮箱地址';
} else if (email.validity.typeMismatch) {
error.textContent = '请输入有效的邮箱地址';
} else {
error.textContent = '';
}
}
function validatePassword() {
const error = document.getElementById('password-error');
if (password.validity.valueMissing) {
error.textContent = '请输入密码';
} else if (password.validity.tooShort) {
error.textContent = `密码至少需要${password.minLength}个字符`;
} else {
error.textContent = '';
}
}
form.addEventListener('submit', function(e) {
validateEmail();
validatePassword();
if (!form.checkValidity()) {
e.preventDefault();
}
});
</script>
FormData对象用于构建表单数据:
<form id="myForm">
<input type="text" name="username" value="东巴文">
<input type="email" name="email" value="test@db-w.cn">
<button type="submit">提交</button>
</form>
<script>
const form = document.getElementById('myForm');
form.addEventListener('submit', function(e) {
e.preventDefault();
// 方式1:从表单创建
const formData = new FormData(form);
// 方式2:手动创建
const formData2 = new FormData();
formData2.append('username', '东巴文');
formData2.append('email', 'test@db-w.cn');
// 发送数据
fetch('/api/submit', {
method: 'POST',
body: formData
})
.then(response => response.json())
.then(data => console.log(data));
});
</script>
东巴文FormData方法:
| 方法 | 说明 | 示例 |
|---|---|---|
append(name, value) |
添加数据 | formData.append('name', 'value') |
delete(name) |
删除数据 | formData.delete('name') |
get(name) |
获取值 | formData.get('name') |
getAll(name) |
获取所有值 | formData.getAll('hobby') |
has(name) |
是否存在 | formData.has('name') |
set(name, value) |
设置值 | formData.set('name', 'value') |
entries() |
所有条目 | formData.entries() |
keys() |
所有键 | formData.keys() |
values() |
所有值 | formData.values() |
<form id="uploadForm">
<input type="file" id="fileInput" name="file" multiple>
<button type="submit">上传</button>
</form>
<script>
const form = document.getElementById('uploadForm');
const fileInput = document.getElementById('fileInput');
form.addEventListener('submit', function(e) {
e.preventDefault();
const formData = new FormData();
// 添加多个文件
for (let file of fileInput.files) {
formData.append('files', file);
}
// 上传
fetch('/api/upload', {
method: 'POST',
body: formData
})
.then(response => response.json())
.then(data => {
console.log('上传成功', data);
})
.catch(error => {
console.error('上传失败', error);
});
});
</script>
autocomplete属性<!-- 开启自动完成 -->
<form autocomplete="on">
<input type="text" name="name" autocomplete="name">
<input type="email" name="email" autocomplete="email">
<input type="tel" name="tel" autocomplete="tel">
<input type="text" name="address" autocomplete="street-address">
</form>
<!-- 关闭自动完成 -->
<form autocomplete="off">
<input type="text" name="captcha" autocomplete="off">
</form>
东巴文autocomplete属性值:
| 属性值 | 说明 | 使用场景 |
|---|---|---|
on |
开启 | 默认值 |
off |
关闭 | 验证码、一次性输入 |
name |
姓名 | 全名 |
email |
邮箱 | 邮箱地址 |
tel |
电话 | 电话号码 |
username |
用户名 | 登录用户名 |
current-password |
当前密码 | 登录密码 |
new-password |
新密码 | 注册/修改密码 |
street-address |
街道地址 | 详细地址 |
cc-number |
信用卡号 | 支付信息 |
<!-- ✅ 推荐:使用正确的类型 -->
<input type="email" name="email">
<input type="tel" name="phone">
<input type="url" name="website">
<!-- ❌ 不推荐:全部使用text -->
<input type="text" name="email">
<input type="text" name="phone">
<!-- ✅ 推荐:添加autocomplete -->
<input type="text" name="name" autocomplete="name">
<input type="email" name="email" autocomplete="email">
<!-- ❌ 不推荐:无autocomplete -->
<input type="text" name="name">
<input type="email" name="email">
<!-- ✅ 推荐:提供建议选项 -->
<input type="text" name="city" list="cities">
<datalist id="cities">
<option value="北京">
<option value="上海">
<option value="广州">
</datalist>
<!-- ✅ 推荐:实时验证 -->
<input type="email" name="email"
oninput="validateEmail(this)"
oninvalid="showError(this)">
<!-- ❌ 不推荐:只在提交时验证 -->
<form onsubmit="return validateForm()">
<!-- ✅ 推荐:使用FormData -->
const formData = new FormData(form);
<!-- ❌ 不推荐:手动拼接数据 -->
const data = 'username=' + username + '&email=' + email;
问题1:以下哪个元素用于显示计算结果?
A. <result>
B. <output>
C. <display>
D. <show>
答案:B
东巴文解释:<output>元素用于显示计算结果或用户操作的结果。HTML中没有<result>、<display>、<show>这些元素。
问题2:以下哪个方法用于检查表单元素的有效性?
A. validate()
B. checkValidity()
C. isValid()
D. testValidity()
答案:B
东巴文解释:checkValidity()方法用于检查表单元素的有效性,返回boolean值。HTML5验证API中没有validate()、isValid()、testValidity()这些方法。
任务:创建一个包含以下特性的高级表单:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>高级表单 - 东巴文</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background: #f5f5f5;
padding: 20px;
}
.container {
max-width: 800px;
margin: 0 auto;
background: white;
padding: 30px;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
}
h1 {
color: #333;
margin-bottom: 30px;
text-align: center;
}
.form-section {
margin-bottom: 30px;
padding: 20px;
background: #f9f9f9;
border-radius: 6px;
}
.form-section h2 {
color: #555;
font-size: 18px;
margin-bottom: 15px;
border-bottom: 2px solid #4CAF50;
padding-bottom: 8px;
}
.form-group {
margin-bottom: 15px;
}
label {
display: block;
margin-bottom: 5px;
color: #555;
font-weight: 500;
}
input[type="text"],
input[type="email"],
input[type="password"],
input[type="date"],
input[type="time"],
input[type="datetime-local"],
input[type="month"],
input[type="week"],
input[type="number"],
input[type="tel"],
input[type="url"],
input[type="search"],
select,
textarea {
width: 100%;
padding: 10px;
border: 1px solid #ddd;
border-radius: 4px;
font-size: 14px;
}
input:focus,
select:focus,
textarea:focus {
outline: none;
border-color: #4CAF50;
box-shadow: 0 0 5px rgba(76, 175, 80, 0.3);
}
input:invalid:not(:placeholder-shown) {
border-color: #f44336;
}
input:valid:not(:placeholder-shown) {
border-color: #4CAF50;
}
.error-message {
color: #f44336;
font-size: 12px;
margin-top: 5px;
}
.range-output {
display: inline-block;
margin-left: 10px;
font-weight: bold;
color: #4CAF50;
}
.color-preview {
display: inline-block;
width: 30px;
height: 30px;
border-radius: 4px;
vertical-align: middle;
margin-left: 10px;
border: 1px solid #ddd;
}
input[type="range"] {
width: calc(100% - 50px);
}
input[type="color"] {
width: 60px;
height: 40px;
padding: 2px;
}
button {
padding: 12px 30px;
background: #4CAF50;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 16px;
margin-right: 10px;
transition: background 0.3s;
}
button:hover {
background: #45a049;
}
button:disabled {
background: #ccc;
cursor: not-allowed;
}
.progress-container {
margin-top: 20px;
display: none;
}
progress {
width: 100%;
height: 20px;
}
.result {
margin-top: 20px;
padding: 15px;
background: #e8f5e9;
border-radius: 4px;
display: none;
}
.result h3 {
color: #4CAF50;
margin-bottom: 10px;
}
.result pre {
background: white;
padding: 10px;
border-radius: 4px;
overflow-x: auto;
}
</style>
</head>
<body>
<div class="container">
<h1>东巴文高级表单示例</h1>
<form id="advancedForm">
<!-- 日期时间类型 -->
<div class="form-section">
<h2>日期时间输入</h2>
<div class="form-group">
<label for="birthday">出生日期</label>
<input type="date" id="birthday" name="birthday" required>
</div>
<div class="form-group">
<label for="appointment">预约时间</label>
<input type="time" id="appointment" name="appointment" required>
</div>
<div class="form-group">
<label for="meeting">会议时间</label>
<input type="datetime-local" id="meeting" name="meeting">
</div>
</div>
<!-- 数字和范围 -->
<div class="form-section">
<h2>数字和范围</h2>
<div class="form-group">
<label for="age">年龄</label>
<input type="number" id="age" name="age" min="1" max="120" value="25">
</div>
<div class="form-group">
<label for="volume">音量</label>
<input type="range" id="volume" name="volume" min="0" max="100" value="50">
<output for="volume" class="range-output">50</output>
</div>
<div class="form-group">
<label for="price">价格(元)</label>
<input type="number" id="price" name="price" min="0" step="0.01" value="99.99">
</div>
</div>
<!-- 颜色选择器 -->
<div class="form-section">
<h2>颜色选择</h2>
<div class="form-group">
<label for="color">主题颜色</label>
<input type="color" id="color" name="color" value="#4CAF50">
<span class="color-preview" id="colorPreview" style="background: #4CAF50;"></span>
<output for="color" class="range-output">#4CAF50</output>
</div>
</div>
<!-- 自动完成 -->
<div class="form-section">
<h2>自动完成建议</h2>
<div class="form-group">
<label for="browser">浏览器</label>
<input type="text" id="browser" name="browser" list="browsers"
placeholder="选择或输入浏览器名称">
<datalist id="browsers">
<option value="Chrome">
<option value="Firefox">
<option value="Safari">
<option value="Edge">
<option value="Opera">
</datalist>
</div>
<div class="form-group">
<label for="city">城市</label>
<input type="text" id="city" name="city" list="cities"
placeholder="选择或输入城市名称">
<datalist id="cities">
<option value="北京">
<option value="上海">
<option value="广州">
<option value="深圳">
<option value="杭州">
</datalist>
</div>
</div>
<!-- 实时验证 -->
<div class="form-section">
<h2>实时验证</h2>
<div class="form-group">
<label for="email">邮箱</label>
<input type="email" id="email" name="email" required
placeholder="请输入邮箱地址">
<span class="error-message" id="email-error"></span>
</div>
<div class="form-group">
<label for="phone">手机号</label>
<input type="tel" id="phone" name="phone"
pattern="[0-9]{11}" required
placeholder="请输入11位手机号">
<span class="error-message" id="phone-error"></span>
</div>
<div class="form-group">
<label for="password">密码</label>
<input type="password" id="password" name="password"
minlength="6" maxlength="20" required
placeholder="6-20个字符">
<span class="error-message" id="password-error"></span>
</div>
</div>
<!-- 提交按钮 -->
<div style="text-align: center; margin-top: 30px;">
<button type="submit">提交表单</button>
<button type="reset">重置</button>
</div>
<!-- 进度条 -->
<div class="progress-container" id="progressContainer">
<progress id="submitProgress" value="0" max="100"></progress>
<p style="text-align: center; margin-top: 10px;">提交中...</p>
</div>
<!-- 结果显示 -->
<div class="result" id="result">
<h3>提交成功!</h3>
<p>表单数据:</p>
<pre id="resultData"></pre>
</div>
</form>
</div>
<script>
const form = document.getElementById('advancedForm');
// 范围滑块实时显示
const volumeInput = document.getElementById('volume');
const volumeOutput = document.querySelector('output[for="volume"]');
volumeInput.addEventListener('input', function() {
volumeOutput.textContent = this.value;
});
// 颜色选择器实时显示
const colorInput = document.getElementById('color');
const colorPreview = document.getElementById('colorPreview');
const colorOutput = document.querySelector('output[for="color"]');
colorInput.addEventListener('input', function() {
colorPreview.style.background = this.value;
colorOutput.textContent = this.value;
});
// 实时验证
const emailInput = document.getElementById('email');
const phoneInput = document.getElementById('phone');
const passwordInput = document.getElementById('password');
emailInput.addEventListener('input', function() {
const error = document.getElementById('email-error');
if (this.validity.valueMissing) {
error.textContent = '请输入邮箱地址';
} else if (this.validity.typeMismatch) {
error.textContent = '请输入有效的邮箱地址';
} else {
error.textContent = '';
}
});
phoneInput.addEventListener('input', function() {
const error = document.getElementById('phone-error');
if (this.validity.valueMissing) {
error.textContent = '请输入手机号';
} else if (this.validity.patternMismatch) {
error.textContent = '请输入11位手机号';
} else {
error.textContent = '';
}
});
passwordInput.addEventListener('input', function() {
const error = document.getElementById('password-error');
if (this.validity.valueMissing) {
error.textContent = '请输入密码';
} else if (this.validity.tooShort) {
error.textContent = `密码至少需要${this.minLength}个字符`;
} else if (this.validity.tooLong) {
error.textContent = `密码最多${this.maxLength}个字符`;
} else {
error.textContent = '';
}
});
// 表单提交
form.addEventListener('submit', function(e) {
e.preventDefault();
if (!form.checkValidity()) {
alert('请正确填写所有必填项!');
return;
}
// 显示进度
const progressContainer = document.getElementById('progressContainer');
const progress = document.getElementById('submitProgress');
progressContainer.style.display = 'block';
// 模拟提交进度
let value = 0;
const interval = setInterval(() => {
value += 10;
progress.value = value;
if (value >= 100) {
clearInterval(interval);
// 显示结果
const formData = new FormData(form);
const data = {};
for (let [key, value] of formData.entries()) {
data[key] = value;
}
document.getElementById('resultData').textContent =
JSON.stringify(data, null, 2);
document.getElementById('result').style.display = 'block';
progressContainer.style.display = 'none';
}
}, 200);
});
</script>
</body>
</html>
</details>
东巴文(db-w.cn) - 让编程学习更有趣、更高效!