Skip to content

hidden 隐藏字段

<input type="hidden"> 是 HTML 中的隐藏输入字段,用户在页面上看不到该控件,但它的值会随表单一起提交。隐藏字段常用于传递表单外的元数据、CSRF 令牌、数据库 ID、状态标识等需要包含在提交数据中但不需要用户直接交互的信息。

前置知识

阅读本节前,建议先了解:file 文件上传

基础概念

什么是 hidden 输入

type="hidden" 创建一个不可见的输入字段,它不会在页面上渲染任何可视元素,但其 namevalue 会作为表单数据的一部分提交到服务器。主要用途:

  • CSRF 防护令牌:传递跨站请求伪造令牌
  • 数据库标识:传递记录 ID(编辑场景)
  • 状态保持:传递页面状态、步骤信息
  • 追踪参数:来源页面、用户 ID 等
  • 关联数据:关联其他表单外部的数据

特点

  • 不可见:不在页面上显示任何可视元素
  • 不可编辑:用户无法直接修改(但可通过开发者工具修改)
  • 值会提交:表单提交时包含 hidden 字段的 name=value
  • 无验证:没有内置的输入验证机制

语法

基本用法

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>hidden 隐藏字段示例</title>
</head>
<body>
    <h2>编辑用户信息</h2>
    <!-- 隐藏字段传递用户 ID -->
    <form action="/user/update" method="post">
        <input type="hidden" name="user_id" value="1024">

        <label for="username">用户名:</label>
        <input type="text" id="username" name="username" value="zhangsan">

        <label for="email">邮箱:</label>
        <input type="email" id="email" name="email" value="zhangsan@example.com">

        <button type="submit">保存修改</button>
    </form>
</body>
</html>

多个隐藏字段

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>多个隐藏字段</title>
</head>
<body>
    <h2>订单确认</h2>
    <form action="/order/confirm" method="post">
        <!-- 订单相关元数据 -->
        <input type="hidden" name="order_id" value="ORD-20250714-001">
        <input type="hidden" name="user_id" value="1024">
        <input type="hidden" name="source" value="mobile_app">
        <input type="hidden" name="timestamp" value="1752470400">

        <h3>收货地址</h3>
        <label for="address">详细地址:</label>
        <textarea id="address" name="address" rows="3"></textarea>

        <button type="submit">确认下单</button>
    </form>
</body>
</html>

详细说明

CSRF 令牌传递

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>CSRF 令牌</title>
</head>
<body>
    <h2>修改密码</h2>
    <form action="/account/change-password" method="post">
        <!-- CSRF 令牌由服务端生成,防止跨站请求伪造 -->
        <input type="hidden" name="csrf_token" value="a1b2c3d4e5f6g7h8i9j0">

        <label for="old-password">旧密码:</label>
        <input type="password" id="old-password" name="old_password" required>

        <label for="new-password">新密码:</label>
        <input type="password" id="new-password" name="new_password" required>

        <label for="confirm-password">确认新密码:</label>
        <input type="password" id="confirm-password" name="confirm_password" required>

        <button type="submit">修改密码</button>
    </form>

    <script>
        // 提交前可以动态设置 CSRF 令牌
        // 实际项目中通常在页面加载时由服务端渲染
        const form = document.querySelector('form');
        const csrfField = form.querySelector('input[name="csrf_token"]');
        console.log('CSRF Token:', csrfField.value);
    </script>
</body>
</html>

JavaScript 动态操作隐藏字段

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>动态隐藏字段</title>
</head>
<body>
    <h2>多步骤表单</h2>
    <form id="multi-step-form" action="/submit" method="post">
        <!-- 动态跟踪当前步骤 -->
        <input type="hidden" id="step" name="step" value="1">
        <!-- 收集之前步骤的数据 -->
        <input type="hidden" id="prev-data" name="prev_data" value="">

        <!-- 步骤 1 -->
        <div id="step-1">
            <h3>第一步:基本信息</h3>
            <label for="name">姓名:</label>
            <input type="text" id="name" name="name">
            <button type="button" onclick="nextStep()">下一步</button>
        </div>

        <!-- 步骤 2(初始隐藏) -->
        <div id="step-2" style="display: none;">
            <h3>第二步:联系方式</h3>
            <label for="phone">手机:</label>
            <input type="tel" id="phone" name="phone">
            <button type="button" onclick="prevStep()">上一步</button>
            <button type="button" onclick="nextStep()">下一步</button>
        </div>

        <!-- 步骤 3(初始隐藏) -->
        <div id="step-3" style="display: none;">
            <h3>第三步:确认</h3>
            <p id="summary"></p>
            <button type="button" onclick="prevStep()">上一步</button>
            <button type="submit">提交</button>
        </div>
    </form>

    <script>
        let currentStep = 1;
        const formData = {};

        function showStep(step) {
            document.querySelectorAll('[id^="step-"]').forEach(el => {
                el.style.display = el.id === `step-${step}` ? 'block' : 'none';
            });
            document.getElementById('step').value = step;
            currentStep = step;
        }

        function nextStep() {
            if (currentStep === 1) {
                formData.name = document.getElementById('name').value;
            }
            if (currentStep === 2) {
                formData.phone = document.getElementById('phone').value;
            }
            if (currentStep === 2) {
                // 显示汇总
                document.getElementById('summary').textContent =
                    `姓名:${formData.name},手机:${formData.phone}`;
                document.getElementById('prev-data').value = JSON.stringify(formData);
            }
            showStep(currentStep + 1);
        }

        function prevStep() {
            showStep(currentStep - 1);
        }
    </script>
</body>
</html>

服务端状态传递

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>服务端状态传递</title>
</head>
<body>
    <h2>服务端渲染的隐藏字段</h2>
    <p>以下隐藏字段由服务端模板引擎生成:</p>

    <form action="/post/edit" method="post">
        <!-- 由服务端填充的实际值 -->
        <input type="hidden" name="post_id" value="42">
        <input type="hidden" name="author_id" value="1024">
        <input type="hidden" name="created_at" value="2025-07-10T08:30:00">
        <input type="hidden" name="version" value="3">

        <label for="title">文章标题:</label>
        <input type="text" id="title" name="title" value="HTML 表单教程">

        <label for="content">文章内容:</label>
        <textarea id="content" name="content" rows="5">表单是 Web 交互的基础...</textarea>

        <button type="submit">保存文章</button>
    </form>

    <!--
        服务端模板示例(伪代码):
        <input type="hidden" name="post_id" value="{{ post.id }}">
        <input type="hidden" name="author_id" value="{{ post.authorId }}">
        <input type="hidden" name="version" value="{{ post.version }}">
    -->
</body>
</html>

disabled 与 hidden 的区别

特性type="hidden"disabled
页面可见不可见可见但灰色
值是否提交提交不提交
用户编辑不可编辑不可编辑
JavaScript 读写可以可以
典型用途传递元数据禁用但不隐藏
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>hidden vs disabled</title>
</head>
<body>
    <h2>hidden 与 disabled 对比</h2>
    <form action="/submit" method="post">
        <!-- 值会提交 -->
        <input type="hidden" name="id" value="42">

        <!-- 值不会提交 -->
        <input type="text" name="readonly_field" value="自动生成" disabled>

        <!-- 可见且只读,值会提交 -->
        <input type="text" name="visible_readonly" value="只读内容" readonly>

        <label for="editable">可编辑:</label>
        <input type="text" id="editable" name="editable" value="用户输入">

        <button type="submit">提交</button>
    </form>

    <p>提交数据将包含:id=42, visible_readonly=只读内容, editable=用户输入</p>
    <p>disabled 字段的数据不会被提交</p>
</body>
</html>

注意事项

安全警示:不要信任隐藏字段的值

隐藏字段对用户是不可见的,但不代表是安全的。用户可以通过浏览器开发者工具轻松查看和修改隐藏字段的值:

javascript
// 用户可以在控制台中执行以下代码修改隐藏字段
document.querySelector('input[name="user_id"]').value = '9999';
document.querySelector('input[name="csrf_token"]').value = 'fake_token';

因此:

  1. 敏感数据不要放在 hidden 字段中(如密码、密钥、价格等)
  2. 服务端必须验证所有提交的数据,包括隐藏字段的值
  3. CSRF 令牌由服务端生成和验证,客户端不应修改
  4. 价格等关键数据应在服务端查询,而非依赖客户端提交的值

不要用 hidden 存储大量数据

虽然技术上可以在 hidden 字段中存储较长的字符串,但这不是好的做法:

html
<!-- 不推荐:存储大量数据 -->
<input type="hidden" name="big_data" value='{"items":[...大量JSON数据...]}'>

更好的做法:

  • 使用服务端 session 存储大数据
  • 使用 localStorage/sessionStorage 存储客户端数据
  • 使用数据库查询获取完整数据

最佳实践

  1. CSRF 防护:在所有修改数据的表单中包含 CSRF 令牌
  2. 编辑场景传 ID:编辑记录时,通过隐藏字段传递记录的唯一标识
  3. 服务端验证:永远不要信任隐藏字段传来的值
  4. 使用语义化命名:为隐藏字段取有意义的 name,便于服务端处理
  5. 避免存储敏感数据:密码、密钥等绝不放入隐藏字段
  6. 动态设置:需要动态值时用 JavaScript 设置,而非硬编码

下一节

继续学习:image 图像按钮

参考链接