Skip to content

HTML 表单与验证

表单基础

HTML表单用于收集用户输入,包含各种输入控件。

基本表单结构

html
<form action="/submit" method="POST" enctype="multipart/form-data">
  <label for="username">用户名:</label>
  <input type="text" id="username" name="username" required>
  
  <label for="password">密码:</label>
  <input type="password" id="password" name="password" required>
  
  <button type="submit">提交</button>
</form>

表单属性

form 属性

html
<form action="/submit" method="POST" enctype="multipart/form-data" 
      target="_blank" autocomplete="on" novalidate>
  <!-- 表单内容 -->
</form>
  • action: 表单提交的URL
  • method: 提交方法(GET/POST)
  • enctype: 编码类型
    • application/x-www-form-urlencoded: 默认
    • multipart/form-data: 文件上传
    • text/plain: 纯文本
  • target: 打开方式(_self/_blank/_parent/_top)
  • autocomplete: 自动完成
  • novalidate: 禁用浏览器验证

输入控件

1. 文本输入

html
<!-- 单行文本 -->
<input type="text" name="username" placeholder="请输入用户名" 
       maxlength="20" required>

<!-- 密码 -->
<input type="password" name="password" placeholder="请输入密码" 
       minlength="6" required>

<!-- 邮箱 -->
<input type="email" name="email" placeholder="请输入邮箱" required>

<!-- URL -->
<input type="url" name="website" placeholder="请输入网址">

<!-- 电话 -->
<input type="tel" name="phone" placeholder="请输入电话">

<!-- 搜索 -->
<input type="search" name="search" placeholder="搜索">

<!-- 多行文本 -->
<textarea name="message" rows="5" cols="40" placeholder="请输入留言" 
          maxlength="500" required></textarea>

2. 数字输入

html
<!-- 数字 -->
<input type="number" name="age" min="0" max="120" step="1" 
       placeholder="年龄">

<!-- 范围 -->
<input type="range" name="volume" min="0" max="100" value="50">

<!-- 日期 -->
<input type="date" name="birthday">

<!-- 时间 -->
<input type="time" name="meeting-time">

<!-- 日期时间 -->
<input type="datetime-local" name="meeting-date">

<!-- 月份 -->
<input type="month" name="month">

<!-- 周 -->
<input type="week" name="week">

3. 选择控件

html
<!-- 单选按钮 -->
<fieldset>
  <legend>性别</legend>
  <input type="radio" id="male" name="gender" value="male" checked>
  <label for="male">男</label>
  
  <input type="radio" id="female" name="gender" value="female">
  <label for="female">女</label>
</fieldset>

<!-- 复选框 -->
<fieldset>
  <legend>兴趣爱好</legend>
  <input type="checkbox" id="reading" name="hobbies" value="reading">
  <label for="reading">阅读</label>
  
  <input type="checkbox" id="music" name="hobbies" value="music">
  <label for="music">音乐</label>
  
  <input type="checkbox" id="sports" name="hobbies" value="sports">
  <label for="sports">运动</label>
</fieldset>

<!-- 下拉选择 -->
<select name="city" required>
  <option value="">请选择城市</option>
  <option value="beijing">北京</option>
  <option value="shanghai">上海</option>
  <option value="guangzhou">广州</option>
</select>

<!-- 多选下拉 -->
<select name="skills" multiple size="4">
  <option value="html">HTML</option>
  <option value="css">CSS</option>
  <option value="javascript">JavaScript</option>
  <option value="python">Python</option>
</select>

<!-- 选项组 -->
<select name="category">
  <optgroup label="前端">
    <option value="html">HTML</option>
    <option value="css">CSS</option>
    <option value="js">JavaScript</option>
  </optgroup>
  <optgroup label="后端">
    <option value="python">Python</option>
    <option value="java">Java</option>
    <option value="node">Node.js</option>
  </optgroup>
</select>

4. 文件上传

html
<!-- 单文件上传 -->
<input type="file" name="avatar" accept="image/*" required>

<!-- 多文件上传 -->
<input type="file" name="files" multiple accept=".jpg,.png,.pdf">

<!-- 文件拖拽区域 -->
<div class="drop-zone">
  <input type="file" name="file" id="file-input" hidden>
  <label for="file-input">拖拽文件到此处或点击上传</label>
</div>

5. 其他控件

html
<!-- 按钮 -->
<button type="submit">提交</button>
<button type="reset">重置</button>
<button type="button">普通按钮</button>

<!-- 隐藏字段 -->
<input type="hidden" name="user-id" value="123">

<!-- 颜色选择器 -->
<input type="color" name="theme-color" value="#ff0000">

<!-- 进度条 -->
<progress value="70" max="100">70%</progress>

<!-- 度量衡 -->
<meter value="0.6" min="0" max="1" low="0.2" high="0.8" optimum="0.5">60%</meter>

<!-- 输出 -->
<output name="result">计算结果</output>

表单验证

HTML5 验证属性

html
<form novalidate>
  <!-- 必填 -->
  <input type="text" name="username" required>
  
  <!-- 最小/最大长度 -->
  <input type="password" name="password" minlength="6" maxlength="20">
  
  <!-- 最小/最大值 -->
  <input type="number" name="age" min="0" max="120">
  
  <!-- 正则表达式 -->
  <input type="text" name="phone" pattern="^1[3-9]\d{9}$" 
         placeholder="请输入手机号">
  
  <!-- 邮箱格式 -->
  <input type="email" name="email" required>
  
  <!-- URL格式 -->
  <input type="url" name="website" placeholder="https://example.com">
  
  <!-- 自定义验证消息 -->
  <input type="text" name="username" required 
         pattern="[a-zA-Z0-9_]{4,16}"
         title="用户名必须是4-16位的字母、数字或下划线">
</form>

验证状态

html
<form>
  <input type="email" name="email" required>
  <span class="error-message"></span>
</form>

<script>
const form = document.querySelector('form');
const emailInput = document.querySelector('input[name="email"]');
const errorMessage = document.querySelector('.error-message');

emailInput.addEventListener('input', function() {
  if (this.validity.valid) {
    errorMessage.textContent = '';
    this.setCustomValidity('');
  } else {
    if (this.validity.valueMissing) {
      errorMessage.textContent = '请输入邮箱地址';
    } else if (this.validity.typeMismatch) {
      errorMessage.textContent = '请输入有效的邮箱地址';
    }
    this.setCustomValidity('请输入有效的邮箱地址');
  }
});

form.addEventListener('submit', function(e) {
  if (!form.checkValidity()) {
    e.preventDefault();
    emailInput.reportValidity();
  }
});
</script>

自定义验证

html
<form id="myForm">
  <input type="password" id="password" name="password" required>
  <input type="password" id="confirmPassword" name="confirmPassword" required>
  <button type="submit">提交</button>
</form>

<script>
const form = document.getElementById('myForm');
const password = document.getElementById('password');
const confirmPassword = document.getElementById('confirmPassword');

confirmPassword.addEventListener('input', function() {
  if (this.value !== password.value) {
    this.setCustomValidity('两次输入的密码不一致');
  } else {
    this.setCustomValidity('');
  }
});

form.addEventListener('submit', function(e) {
  if (!form.checkValidity()) {
    e.preventDefault();
    form.reportValidity();
  }
});
</script>

表单增强

自动完成

html
<form autocomplete="on">
  <label for="username">用户名:</label>
  <input type="text" id="username" name="username" autocomplete="username">
  
  <label for="email">邮箱:</label>
  <input type="email" id="email" name="email" autocomplete="email">
  
  <label for="password">密码:</label>
  <input type="password" id="password" name="password" autocomplete="new-password">
  
  <label for="address">地址:</label>
  <input type="text" id="address" name="address" autocomplete="street-address">
</form>

禁用和只读

html
<!-- 禁用 -->
<input type="text" name="disabled" disabled>
<select name="disabled-select" disabled>
  <option>选项1</option>
</select>
<button type="submit" disabled>提交</button>

<!-- 只读 -->
<input type="text" name="readonly" value="只读内容" readonly>
<textarea name="readonly-text" readonly>只读内容</textarea>

表单分组

html
<form>
  <fieldset>
    <legend>个人信息</legend>
    <label for="name">姓名:</label>
    <input type="text" id="name" name="name">
    
    <label for="age">年龄:</label>
    <input type="number" id="age" name="age">
  </fieldset>
  
  <fieldset>
    <legend>联系方式</legend>
    <label for="email">邮箱:</label>
    <input type="email" id="email" name="email">
    
    <label for="phone">电话:</label>
    <input type="tel" id="phone" name="phone">
  </fieldset>
</form>

面试常见问题

1. GET 和 POST 的区别?

  • GET: 参数在URL中,有长度限制,可缓存,可收藏
  • POST: 参数在请求体中,无长度限制,不可缓存,更安全
html
<form action="/search" method="GET">
  <input type="text" name="q">
  <button type="submit">搜索</button>
</form>

<form action="/submit" method="POST">
  <input type="text" name="data">
  <button type="submit">提交</button>
</form>

2. enctype 的三种类型?

  • application/x-www-form-urlencoded: 默认,URL编码
  • multipart/form-data: 文件上传
  • text/plain: 纯文本
html
<form action="/upload" method="POST" enctype="multipart/form-data">
  <input type="file" name="file">
  <button type="submit">上传</button>
</form>

3. required 属性的作用?

required属性标记输入字段为必填,如果用户未填写,表单无法提交。

html
<input type="text" name="username" required>

4. 如何禁用浏览器默认验证?

在form标签上添加novalidate属性。

html
<form novalidate>
  <input type="email" name="email">
  <button type="submit">提交</button>
</form>

5. 如何实现密码确认验证?

使用JavaScript自定义验证,比较两次输入的密码是否一致。

javascript
const password = document.getElementById('password');
const confirmPassword = document.getElementById('confirmPassword');

confirmPassword.addEventListener('input', function() {
  if (this.value !== password.value) {
    this.setCustomValidity('两次输入的密码不一致');
  } else {
    this.setCustomValidity('');
  }
});

通过理解HTML表单的各种输入控件和验证机制,可以构建用户友好、安全可靠的表单界面。

好好学习,天天向上