跳转到内容

在 Astro 页面中构建 HTML 表单

按需渲染的 Astro 页面既可以显示表单,也可以处理表单。在本指南中,你将使用一个标准的 HTML 表单向服务器提交数据。你的 frontmatter 脚本将在服务器上处理这些数据,而不会向客户端发送任何 JavaScript。

  1. 创建或确定一个 .astro 页面,它将包含你的表单和处理代码。例如,你可以添加一个注册页面

    src/pages/register.astro
    ---
    ---
    <h1>Register</h1>
  2. 向页面添加一个带有一些输入的 <form> 标签。每个输入都应该有一个 name 属性来描述该输入的值。

    确保包含一个 <button><input type="submit"> 元素来提交表单。

    src/pages/register.astro
    ---
    ---
    <h1>Register</h1>
    <form>
    <label>
    Username:
    <input type="text" name="username" />
    </label>
    <label>
    Email:
    <input type="email" name="email" />
    </label>
    <label>
    Password:
    <input type="password" name="password" />
    </label>
    <button>Submit</button>
    </form>
  3. 使用验证属性来提供基本的客户端验证,即使在 JavaScript 被禁用的情况下也能工作。

    在这个例子中,

    • required 会阻止表单提交,直到字段被填写。
    • minlength 为输入文本设置了最小必需长度。
    • type="email" 也引入了验证,它只接受有效的电子邮件格式。
    src/pages/register.astro
    ---
    ---
    <h1>Register</h1>
    <form>
    <label>
    Username:
    <input type="text" name="username" required />
    </label>
    <label>
    Email:
    <input type="email" name="email" required />
    </label>
    <label>
    Password:
    <input type="password" name="password" required minlength="6" />
    </label>
    <button>Submit</button>
    </form>
  4. 表单提交将导致浏览器再次请求该页面。将表单的数据传输 method 更改为 POST,以将表单数据作为 Request 主体的一部分发送,而不是作为 URL 参数发送。

    src/pages/register.astro
    ---
    ---
    <h1>Register</h1>
    <form method="POST">
    <label>
    Username:
    <input type="text" name="username" required />
    </label>
    <label>
    Email:
    <input type="email" name="email" required />
    </label>
    <label>
    Password:
    <input type="password" name="password" required minlength="6" />
    </label>
    <button>Submit</button>
    </form>
  5. 在 frontmatter 中检查 POST 方法,并使用 Astro.request.formData() 访问表单数据。将其包装在 try ... catch 块中,以处理 POST 请求不是由表单发送且 formData 无效的情况。

    src/pages/register.astro
    ---
    export const prerender = false; // Not needed in 'server' mode
    if (Astro.request.method === "POST") {
    try {
    const data = await Astro.request.formData();
    const name = data.get("username");
    const email = data.get("email");
    const password = data.get("password");
    // Do something with the data
    } catch (error) {
    if (error instanceof Error) {
    console.error(error.message);
    }
    }
    }
    ---
    <h1>Register</h1>
    <form method="POST">
    <label>
    Username:
    <input type="text" name="username" required />
    </label>
    <label>
    Email:
    <input type="email" name="email" required />
    </label>
    <label>
    Password:
    <input type="password" name="password" required minlength="6" />
    </label>
    <button>Submit</button>
    </form>
  6. 在服务器上验证表单数据。这应该包括在客户端完成的相同验证,以防止对你的端点进行恶意提交,并支持没有表单验证的罕见旧版浏览器。

    它还可以包括无法在客户端完成的验证。例如,本例检查电子邮件是否已存在于数据库中。

    错误消息可以通过将它们存储在一个 errors 对象中并在模板中访问它来发送回客户端。

    src/pages/register.astro
    ---
    export const prerender = false; // Not needed in 'server' mode
    import { isRegistered, registerUser } from "../../data/users"
    import { isValidEmail } from "../../utils/isValidEmail";
    const errors = { username: "", email: "", password: "" };
    if (Astro.request.method === "POST") {
    try {
    const data = await Astro.request.formData();
    const name = data.get("username");
    const email = data.get("email");
    const password = data.get("password");
    if (typeof name !== "string" || name.length < 1) {
    errors.username += "Please enter a username. ";
    }
    if (typeof email !== "string" || !isValidEmail(email)) {
    errors.email += "Email is not valid. ";
    } else if (await isRegistered(email)) {
    errors.email += "Email is already registered. ";
    }
    if (typeof password !== "string" || password.length < 6) {
    errors.password += "Password must be at least 6 characters. ";
    }
    const hasErrors = Object.values(errors).some(msg => msg)
    if (!hasErrors) {
    await registerUser({name, email, password});
    return Astro.redirect("/login");
    }
    } catch (error) {
    if (error instanceof Error) {
    console.error(error.message);
    }
    }
    }
    ---
    <h1>Register</h1>
    <form method="POST">
    <label>
    Username:
    <input type="text" name="username" />
    </label>
    {errors.username && <p>{errors.username}</p>}
    <label>
    Email:
    <input type="email" name="email" required />
    </label>
    {errors.email && <p>{errors.email}</p>}
    <label>
    Password:
    <input type="password" name="password" required minlength="6" />
    </label>
    {errors.password && <p>{errors.password}</p>}
    <button>Register</button>
    </form>
贡献 社区 赞助