您当前的位置:首页 > 计算机 > 编程开发 > Html+Div+Css(前端)

HTML `<form>` 标签(表单)深度解析

时间:10-23来源:作者:点击数:

HTML <form> 标签(表单)深度解析

目录

  1. 引言:HTML <form> 标签简介
    • 1.1 什么是 HTML 表单?
    • 1.2 <form> 标签的语义作用
  2. <form> 标签详解
    • 2.1 定义与目的
    • 2.2 视觉呈现
    • 2.3 语法
    • 2.4 核心属性
      • action
      • method
      • enctype
      • autocomplete
      • name
      • target
      • novalidate
  3. <form> 与表单元素
    • 3.1 常见的表单控件
    • 3.2 表单结构化元素
  4. action 与 method 属性详解
    • 4.1 method="GET"
    • 4.2 method="POST"
    • 4.3 何时选择 GET 或 POST
  5. enctype 属性详解
    • 5.1 application/x-www-form-urlencoded (默认)
    • 5.2 multipart/form-data
    • 5.3 text/plain
  6. 表单验证 (Form Validation)
    • 6.1 客户端验证 (HTML5)
    • 6.2 服务器端验证
  7. 可访问性 (Accessibility) 考量
  8. 浏览器兼容性
  9. 最佳实践
  10. 代码示例
    • 10.1 基本登录表单 (POST)
    • 10.2 带有文件上传和文本域的联系表单
    • 10.3 搜索表单 (GET)
    • 10.4 注册表单与 HTML5 验证
    • 10.5 包含 fieldset 和 legend 的表单
  11. 总结

1. 引言:HTML <form> 标签简介

在互联网世界中,用户与网站的交互方式多种多样,而表单是其中最基础、最重要的一种。无论是登录、注册、提交评论、进行搜索还是在线购物,都离不开表单。HTML <form> 标签正是构建这些交互界面的基石。

1.1 什么是 HTML 表单?

HTML 表单是用于收集用户输入信息的 HTML 元素集合。它包含各种交互式控件,如文本字段、复选框、单选按钮、提交按钮等,用户可以通过这些控件向服务器发送数据。

1.2 <form> 标签的语义作用

<form> 标签不仅仅是一个容器,它具有重要的语义作用。它明确告诉浏览器、屏幕阅读器、搜索引擎爬虫和其他解析工具,其包裹的内容是一个用于数据提交的表单。这意味着它将收集的数据按照特定的方式(由 method 和 action 属性定义)发送到服务器。这种语义确保了数据的正确处理和页面的交互性。

2. <form> 标签详解

2.1 定义与目的

HTML <form> 标签用于定义一个 HTML 表单,它是一个容器,用于封装各种表单控件(如输入字段、选择列表、按钮等),这些控件收集到的用户数据最终会根据 <form> 标签的属性设置发送到服务器。

2.2 视觉呈现

<form> 标签本身通常没有默认的视觉样式。它只是一个逻辑上的容器。其内部的表单控件(如输入框、按钮)才会呈现出各自的默认视觉样式,这些样式可以通过 CSS 进行修改。

2.3 语法

<form> 标签是一个块级元素(block-level element),它需要开始标签 <form> 和结束标签 </form>

<form action="/submit-data" method="post">
    <!-- 这里放置各种表单控件,如 input, textarea, button 等 -->
    <input type="text" name="username">
    <button type="submit">提交</button>
</form>
2.4 核心属性

<form> 标签支持所有全局属性 (Global Attributes),但有几个核心属性对表单的功能至关重要:

  • action (必需属性):
    • 作用:指定表单数据提交到哪个 URL。当用户点击提交按钮时,浏览器会将表单数据发送到此 URL。
    • :一个有效的 URL。可以是相对路径 (/submit-data) 或绝对路径 (https://example.com/submit-data)。
    • 注意:如果未指定 action 属性,数据将提交到当前页面 URL。
  • method (必需属性):
    • 作用:指定浏览器如何发送表单数据到 action URL。这是 HTTP 请求的类型。
      • GET (默认值):数据会以 URL 查询字符串的形式附加到 action URL 后面,可见于浏览器地址栏。
      • POST:数据会以 HTTP 请求体(request body)的形式发送,不可见于浏览器地址栏。
    • 注意:选择 GET 还是 POST 有重要的功能和安全考量,将在后续章节详细讨论。
  • enctype
    • 作用:指定表单数据在提交到服务器时应如何编码。这个属性只有在 method="post" 时才有效。
      • application/x-www-form-urlencoded (默认值):所有字符在发送前进行 URL 编码。适用于绝大多数表单数据(文本、数字等)。
      • multipart/form-data:不进行任何编码。当表单包含文件上传 (<input type="file">) 时,必须使用此值。
      • text/plain:空格转换为 “+” 号,但不进行其他特殊字符编码。主要用于调试目的,不推荐用于实际数据提交。
  • autocomplete
    • 作用:指示浏览器是否应自动填充表单字段。
      • on (默认值):允许浏览器根据用户历史输入自动填充。
      • off:禁用浏览器自动填充。
    • 注意:对于敏感信息(如密码、银行卡号),即使设置为 on,现代浏览器也可能不自动填充。出于安全考虑,对于登录密码等,通常建议在 <input> 标签上设置 autocomplete="current-password" 或 autocomplete="new-password" 而非禁用整个表单。
  • name
    • 作用:为表单指定一个名称。在 JavaScript 中可以通过 document.forms.name 访问表单。
    • :一个字符串。
    • 注意:现代 HTML 中,通常使用 id 属性来识别和操作表单,因为 id 具有唯一性。
  • target
    • 作用:指定提交表单后,服务器响应在哪个目标窗口或框架中显示。
      • _self (默认值):响应在当前窗口/标签页中加载。
      • _blank:响应在一个新窗口/标签页中加载。
      • _parent:响应在父级框架中加载。
      • _top:响应在顶层窗口加载 (如果表单在一个框架中)。
      • framename:响应在指定名称的 <iframe> 中加载。
  • novalidate
    • 作用:一个布尔属性。如果存在,表示在提交表单时,不进行 HTML5 自带的客户端表单验证。
    • novalidate (布尔属性,只需存在即为 true)。
    • 注意:这通常用于当你希望完全通过 JavaScript 进行自定义客户端验证,或者只依赖服务器端验证时。

3. <form> 与表单元素

<form> 标签是表单控件的容器。这些控件可以是用户输入信息的字段,也可以是用于提交表单的按钮。

3.1 常见的表单控件
  • <input>:最通用的表单元素,通过 type 属性定义多种类型(text, password, email, number, checkbox, radio, file, submit, reset, button, hidden, date, time, url, tel 等)。
  • <textarea>:多行文本输入区域。
  • <select> 和 <option>:下拉选择列表。
  • <button>:可点击的按钮,type="submit" 用于提交表单,type="reset" 用于重置表单,type="button" 为普通按钮。
  • <datalist>:为 <input> 元素提供预定义选项列表。
  • <output>:显示计算结果。
  • <progress>:显示任务的进度。
  • <meter>:显示已知范围内的标量值。
3.2 表单结构化元素
  • <label>:定义表单控件的标签,增强可访问性。
  • <fieldset>:用于对表单中的相关元素进行分组。
  • <legend>:为 <fieldset> 元素定义标题。

4. action 与 method 属性详解

这两个属性是 <form> 标签功能的核心,决定了数据发送的目的地和方式。

4.1 method="GET"
  • 数据可见性:表单数据会附加到 action URL 的末尾,形成查询字符串(例如:url?name=value&name2=value2),在浏览器地址栏中可见。
  • 数据量限制:URL 的长度有限制(不同浏览器和服务器有差异,通常在几千字符内),因此 GET 请求不适合提交大量数据。
  • 安全性:由于数据在 URL 中可见,不适合提交敏感信息(如密码、银行卡号)。
  • 缓存与书签GET 请求可以被浏览器缓存,也可以被用户添加书签。
  • 幂等性GET 请求应该是幂等的,即重复提交多次不应引起服务器端资源状态的改变(例如,多次搜索不会创建新的资源)。
  • 适用场景:搜索查询、筛选条件、请求页面内容等不改变服务器状态的操作。
4.2 method="POST"
  • 数据可见性:表单数据包含在 HTTP 请求的请求体(Request Body)中,不会在浏览器地址栏中显示。
  • 数据量限制:对数据量没有严格限制,可以提交大量数据,包括文件。
  • 安全性:相对于 GET 更适合提交敏感信息,因为数据不直接暴露在 URL 中。但需要注意的是,POST 请求本身也不是加密的,如果需要加密,应使用 HTTPS。
  • 缓存与书签POST 请求通常不会被浏览器缓存,也不能被用户添加书签。
  • 幂等性POST 请求不是幂等的,重复提交可能会导致创建重复资源或多次执行操作(例如,重复提交订单可能会创建多个订单)。
  • 适用场景:用户注册、登录、提交评论、文件上传、修改数据、删除数据、提交订单等会改变服务器状态的操作。
4.3 何时选择 GET 或 POST
特性 GET POST
数据位置 URL 查询字符串 HTTP 请求体
可见性 可见于地址栏 不可见于地址栏
数据量 有限(URL 长度限制) 无严格限制
敏感信息 不推荐 推荐(配合 HTTPS 更安全)
缓存/书签 可缓存,可书签 不可缓存,不可书签
幂等性 幂等(重复请求无副作用) 非幂等(重复请求可能有副作用)
适用操作 获取数据,不改变服务器状态 提交数据,改变服务器状态
默认 enctype 无效(数据编码在 URL 中) application/x-www-form-urlencoded
文件上传 不支持 支持 (enctype="multipart/form-data")

5. enctype 属性详解

enctype 属性在 method="post" 时特别重要,它指示了浏览器如何编码表单数据。

5.1 application/x-www-form-urlencoded (默认)
  • 编码方式:所有字符在发送到服务器之前都进行 URL 编码(例如,空格被替换为 + 符号,特殊字符转换为百分号编码)。
  • 适用场景:这是大多数表单的默认编码类型,适用于提交文本、数字、日期等简单数据。
  • 示例:当用户输入 “Hello World!”,会被编码为 “Hello+World%21”。
5.2 multipart/form-data
  • 编码方式:数据被分解成多个部分(multi-part),每个部分都有自己的头信息(如 Content-DispositionContent-Type),然后以二进制流的形式发送。
  • 适用场景当表单中包含文件上传 (<input type="file">) 时,必须使用此编码类型。
  • 重要性:如果上传文件时不使用此编码,文件内容将无法正确传输到服务器。
5.3 text/plain
  • 编码方式:数据以纯文本形式发送,空格转换为 + 符号,但其他特殊字符不进行编码。
  • 适用场景不推荐用于实际的生产环境,因为它不安全且不兼容大多数服务器端处理表单数据的机制。主要用于调试或特殊情况下需要查看未经编码的原始数据。

6. 表单验证 (Form Validation)

表单验证是确保用户输入数据有效和符合预期格式的关键步骤。

6.1 客户端验证 (HTML5)

HTML5 引入了许多内置的客户端验证功能,可以在数据提交到服务器之前进行检查,提供即时反馈。

  • required:字段必填。
  • type="email":要求输入有效的电子邮件格式。
  • type="url":要求输入有效的 URL 格式。
  • type="number":要求输入数字。
  • min / max:为 type="number" 或 type="range" 设置最小值和最大值。
  • minlength / maxlength:为文本输入设置最小和最大长度。
  • pattern:使用正则表达式定义输入模式。
  • title:与 pattern 结合使用,提供验证失败时的提示信息。

示例

<input type="email" name="user_email" required pattern="[^@\s]+@[^@\s]+\.[^@\s]+" title="请输入有效的电子邮件地址">

如果 novalidate 属性存在于 <form> 标签上,则所有这些客户端验证都会被禁用。

6.2 服务器端验证

无论是否进行客户端验证,服务器端验证都是必不可少的

  • 安全性:客户端验证可以被绕过(例如通过禁用 JavaScript),因此服务器端验证是防止恶意数据和确保数据完整性的唯一可靠方式。
  • 数据完整性:确保数据符合业务规则和数据库约束。
  • 客户端验证是提高用户体验的第一道防线,服务器端验证是数据安全的最后一道防线。

7. 可访问性 (Accessibility) 考量

构建可访问的表单对所有用户都非常重要,特别是使用辅助技术的用户。

  • 使用 <label> 元素:始终为每个表单控件提供一个 <label> 标签,并使用 for 属性将其与相应的控件通过 id 关联起来。
    <label for="username">用户名:</label>
    <input type="text" id="username" name="username">
    
    这使得屏幕阅读器可以正确地将标签读给用户,并且用户点击标签文本也能激活相应的输入框。
  • 使用 <fieldset> 和 <legend>:对相关的表单控件进行逻辑分组,并提供一个描述性的标题。这有助于屏幕阅读器用户理解表单的结构。
    <fieldset>
        <legend>联系方式</legend>
        <label for="email">邮箱:</label>
        <input type="email" id="email" name="email">
        <!-- 其他联系方式字段 -->
    </fieldset>
    
  • 提供清晰的错误信息:当验证失败时,提供清晰、具体且可访问的错误信息,并确保屏幕阅读器能够识别这些错误。
  • 键盘导航:确保表单可以通过键盘Tab键顺序导航。
  • 无障碍提示:使用 aria-* 属性提供额外的无障碍提示,例如 aria-describedby 将输入字段与描述性文本关联。

8. 浏览器兼容性

<form> 标签是 HTML 的核心元素,并且得到了所有现代浏览器和几乎所有旧版本浏览器的广泛支持。HTML5 的表单验证属性也得到了主流浏览器的良好支持。你可以放心地在网页中使用它。

9. 最佳实践

  • 语义化优先:始终使用 <form> 标签来封装需要提交到服务器的数据。
  • 正确选择 method 和 enctype:根据表单的功能和数据类型,选择合适的 HTTP 方法和编码类型。文件上传必须使用 multipart/form-data
  • 始终使用 <label>:为了可访问性和用户体验,为每个表单控件(特别是 <input><textarea><select>) 提供明确的 <label>
  • 利用 HTML5 验证:尽可能利用 HTML5 内置的验证属性提供客户端验证,减少不必要的服务器请求,并提供即时用户反馈。
  • 不可或缺的服务器端验证:客户端验证只是辅助,服务器端验证才是数据安全的最后保障。
  • 结构化表单:使用 <fieldset> 和 <legend> 组织复杂表单,提高可读性和可访问性。
  • 用户体验:提供清晰的指示、友好的错误信息和适当的默认值,减少用户的输入负担。
  • 安全性:对于敏感数据,始终使用 HTTPS。服务器端应采取措施防止 CSRF、XSS 等攻击。

10. 代码示例

10.1 基本登录表单 (POST)
<!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>
        body { font-family: sans-serif; margin: 20px; }
        form { width: 300px; padding: 20px; border: 1px solid #ccc; border-radius: 5px; }
        div { margin-bottom: 10px; }
        label { display: block; margin-bottom: 5px; font-weight: bold; }
        input[type="text"], input[type="password"] {
            width: calc(100% - 10px);
            padding: 8px;
            border: 1px solid #ddd;
            border-radius: 3px;
        }
        button {
            background-color: #007bff;
            color: white;
            padding: 10px 15px;
            border: none;
            border-radius: 3px;
            cursor: pointer;
            width: 100%;
        }
        button:hover { background-color: #0056b3; }
    </style>
</head>
<body>
    <h1>用户登录</h1>
    <form action="/login" method="post" autocomplete="on">
        <div>
            <label for="username">用户名:</label>
            <input type="text" id="username" name="username" required>
        </div>
        <div>
            <label for="password">密码:</label>
            <input type="password" id="password" name="password" required autocomplete="current-password">
        </div>
        <button type="submit">登录</button>
    </form>
</body>
</html>

效果预览

在这里插入图片描述
10.2 带有文件上传和文本域的联系表单
<!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>
        body { font-family: sans-serif; margin: 20px; }
        form { width: 400px; padding: 20px; border: 1px solid #ccc; border-radius: 5px; }
        div { margin-bottom: 15px; }
        label { display: block; margin-bottom: 5px; font-weight: bold; }
        input[type="text"], input[type="email"], textarea {
            width: calc(100% - 10px);
            padding: 8px;
            border: 1px solid #ddd;
            border-radius: 3px;
        }
        textarea { resize: vertical; min-height: 80px; }
        input[type="file"] { border: none; }
        button {
            background-color: #28a745;
            color: white;
            padding: 10px 15px;
            border: none;
            border-radius: 3px;
            cursor: pointer;
            width: 100%;
        }
        button:hover { background-color: #218838; }
    </style>
</head>
<body>
    <h1>联系我们</h1>
    <form action="/contact" method="post" enctype="multipart/form-data">
        <div>
            <label for="name">您的姓名:</label>
            <input type="text" id="name" name="user_name" required>
        </div>
        <div>
            <label for="email">您的邮箱:</label>
            <input type="email" id="email" name="user_email" required>
        </div>
        <div>
            <label for="message">您的留言:</label>
            <textarea id="message" name="user_message" rows="5" required></textarea>
        </div>
        <div>
            <label for="attachment">上传附件 (可选):</label>
            <input type="file" id="attachment" name="user_attachment">
        </div>
        <button type="submit">发送消息</button>
    </form>
</body>
</html>

效果预览

在这里插入图片描述
10.3 搜索表单 (GET)
<!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>
        body { font-family: sans-serif; margin: 20px; }
        form { display: flex; align-items: center; width: 400px; }
        input[type="search"] {
            flex-grow: 1;
            padding: 10px;
            border: 1px solid #007bff;
            border-radius: 5px 0 0 5px;
            font-size: 1em;
        }
        button {
            background-color: #007bff;
            color: white;
            padding: 10px 15px;
            border: none;
            border-radius: 0 5px 5px 0;
            cursor: pointer;
            font-size: 1em;
        }
        button:hover { background-color: #0056b3; }
    </style>
</head>
<body>
    <h1>搜索本站</h1>
    <form action="/search" method="get">
        <label for="search-query" class="sr-only">搜索关键词:</label>
        <input type="search" id="search-query" name="q" placeholder="输入搜索关键词..." required>
        <button type="submit">搜索</button>
    </form>
    <p class="sr-only">在实际应用中,`class="sr-only"` 会隐藏标签但保留其可访问性。</p>
</body>
</html>

效果预览

在这里插入图片描述
10.4 注册表单与 HTML5 验证
<!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>
        body { font-family: sans-serif; margin: 20px; }
        form { width: 350px; padding: 20px; border: 1px solid #ccc; border-radius: 5px; }
        div { margin-bottom: 15px; }
        label { display: block; margin-bottom: 5px; font-weight: bold; }
        input[type="text"], input[type="email"], input[type="password"] {
            width: calc(100% - 10px);
            padding: 8px;
            border: 1px solid #ddd;
            border-radius: 3px;
        }
        input:invalid { border-color: red; } /* 验证失败时的视觉反馈 */
        input:valid { border-color: green; }  /* 验证成功时的视觉反馈 */
        button {
            background-color: #ffc107;
            color: #333;
            padding: 10px 15px;
            border: none;
            border-radius: 3px;
            cursor: pointer;
            width: 100%;
        }
        button:hover { background-color: #e0a800; }
    </style>
</head>
<body>
    <h1>新用户注册</h1>
    <form action="/register" method="post">
        <div>
            <label for="reg-username">用户名 (5-15字符):</label>
            <input type="text" id="reg-username" name="username" required minlength="5" maxlength="15">
        </div>
        <div>
            <label for="reg-email">邮箱:</label>
            <input type="email" id="reg-email" name="email" required>
        </div>
        <div>
            <label for="reg-password">密码 (至少8位,包含大小写字母和数字):</label>
            <input type="password" id="reg-password" name="password" required
                   pattern="(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,}"
                   title="密码必须至少8位,包含至少一个大写字母,一个小写字母和一个数字">
        </div>
        <div>
            <label for="confirm-password">确认密码:</label>
            <input type="password" id="confirm-password" name="confirm_password" required>
        </div>
        <button type="submit">注册</button>
    </form>

    <script>
        // 简单的客户端JS验证,确保确认密码与密码一致 (HTML5无内置功能)
        const password = document.getElementById('reg-password');
        const confirmPassword = document.getElementById('confirm-password');

        function validatePassword(){
            if(password.value != confirmPassword.value) {
                confirmPassword.setCustomValidity("两次输入的密码不匹配");
            } else {
                confirmPassword.setCustomValidity('');
            }
        }

        password.onchange = validatePassword;
        confirmPassword.onkeyup = validatePassword;
    </script>
</body>
</html>

效果预览

在这里插入图片描述
10.5 包含 fieldset 和 legend 的表单
<!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>
        body { font-family: sans-serif; margin: 20px; }
        form { width: 500px; padding: 20px; border: 1px solid #ccc; border-radius: 5px; }
        fieldset { border: 1px solid #ddd; padding: 15px; margin-bottom: 20px; border-radius: 4px; }
        legend { font-weight: bold; color: #333; padding: 0 10px; }
        div { margin-bottom: 10px; }
        label { display: block; margin-bottom: 5px; font-weight: normal; }
        input[type="text"], input[type="email"], select {
            width: calc(100% - 10px);
            padding: 8px;
            border: 1px solid #ddd;
            border-radius: 3px;
        }
        button {
            background-color: #17a2b8;
            color: white;
            padding: 10px 15px;
            border: none;
            border-radius: 3px;
            cursor: pointer;
            width: 100%;
        }
        button:hover { background-color: #138496; }
    </style>
</head>
<body>
    <h1>填写订单信息</h1>
    <form action="/place-order" method="post">
        <fieldset>
            <legend>个人信息</legend>
            <div>
                <label for="first-name">姓氏:</label>
                <input type="text" id="first-name" name="first_name" required>
            </div>
            <div>
                <label for="last-name">名字:</label>
                <input type="text" id="last-name" name="last_name" required>
            </div>
            <div>
                <label for="order-email">邮箱:</label>
                <input type="email" id="order-email" name="email" required>
            </div>
        </fieldset>

        <fieldset>
            <legend>配送地址</legend>
            <div>
                <label for="address">地址:</label>
                <input type="text" id="address" name="address" required>
            </div>
            <div>
                <label for="city">城市:</label>
                <input type="text" id="city" name="city" required>
            </div>
            <div>
                <label for="zip-code">邮编:</label>
                <input type="text" id="zip-code" name="zip_code" pattern="[0-9]{6}" title="请输入6位数字邮编" required>
            </div>
        </fieldset>

        <button type="submit">提交订单</button>
    </form>
</body>
</html>

效果预览

在这里插入图片描述

11. 总结

为您详尽解析了 HTML <form> 标签。

核心要点回顾

  • 语义化容器<form> 标签是收集用户输入数据并将其发送到服务器的语义化容器。
  • 核心属性
    • action:数据提交的 URL。
    • method:数据提交的 HTTP 方法 (GET 或 POST)。
    • enctype:数据编码类型,文件上传必须使用 multipart/form-data
  • GET vs POSTGET 适用于获取数据(数据可见,可缓存),POST 适用于提交数据(数据隐藏,可上传文件,适合敏感操作)。
  • 表单控件:与 <input><textarea><select><button> 等各种表单元素配合使用。
  • 结构化元素<label><fieldset><legend> 用于提升表单结构和可访问性。
  • 表单验证:利用 HTML5 客户端验证 (requiredtypepattern 等) 提高用户体验,但服务器端验证是数据安全的最后防线
  • 可访问性:通过正确使用 <label><fieldset><legend>,确保表单对所有用户友好。
  • 最佳实践:遵循语义化、安全性、可访问性和用户体验的原则来构建表单。

通过正确理解和使用 <form> 标签及其相关属性和元素,您可以创建功能强大、用户友好且安全可靠的交互式网页。

方便获取更多学习、工作、生活信息请关注本站微信公众号城东书院 微信服务号城东书院 微信订阅号
推荐内容
相关内容
栏目更新
栏目热门
本栏推荐