我们将使用 Next.js 和 Netlify 创建一个联系表单,该表单会显示确认屏幕并具有增强的垃圾邮件检测功能。
Next.js 是一个强大的 React 框架,用于开发可扩展的高性能 React 应用程序。 通过将 Next.js 网站与 Netlify 的技术集成,我们可以快速启动并运行一个可用的联系表单,而无需编写任何服务器端代码。
设置表单以由 Netlify 处理的过程不仅相对快速,而且入门也是免费的(每个托管在 Netlify 上的网站最多可享受 100 次免费提交)。 表单提交会自动通过 Netlify 的内置垃圾邮件过滤器(使用 Akismet),并且还可以配置其他选项以提高垃圾邮件检测级别。

创建联系表单
在 Next.js 应用程序中,我们应该创建一个 ContactForm
组件,以在联系页面内渲染联系表单。 如果您希望此表单在 /contact
处渲染,则应在 pages/contact.js
文件中使用下面带有标签和输入字段的 ContactForm
组件。
const ContactForm = (
<form
name="contact-form"
method="POST"
action="contact/?success=true"
>
<label htmlFor="name">Name *</label>
<input
id="name"
name="name"
required
type="text"
/>
<label htmlFor="company">Company *</label>
<input id="company" name="company" required type="text" />
<label htmlFor="email">E-mail Address *</label>
<input id="email" type="email" name="email" required />
<label htmlFor="message">Message *</label>
<textarea id="message" name="message" required></textarea>
<button type="submit">Submit</button>
</form>
);
上述标记是渲染包含姓名、公司、电子邮件地址和消息字段以及提交按钮的表单所必需的。 提交表单时,根据表单操作的值,它应该从 /contact
重定向到 contact/?success=true
。 目前,带和不带成功查询参数的页面的外观还没有区别,但我们稍后会更新。
到目前为止,我们的 Contact.js
文件如下所示
import React from "react";
const ContactPage = () => {
const ContactForm = (/* code in above code sample*/)
return (
<div>
<h1>Contact Us</h1>
{ContactForm}
</div>
);
};
export default ContactPage;
现在我们已经设置了基本表单,在添加其他信息以便 Netlify 在以后的站点部署期间自动识别表单后,真正的魔力就会出现。 为此,我们应该更新表单以具有 data-netlify="true"
属性和一个包含我们联系表单名称的隐藏输入字段。 在 Netlify 中,一旦我们在仪表板中导航到我们的站点,然后点击“表单”选项卡,我们就可以根据我们在隐藏字段中输入的名称查看表单响应。 重要的是,如果您的站点中有多个表单,则它们应具有唯一的名称,以便 Netlify 能正确记录它们。
<form
method="POST"
name="contact-form"
action="contact/?success=true"
data-netlify="true"
>
<input type="hidden" name="form-name" value="contact-form" />
成功将站点部署到 Netlify 并使用 data-netlify
属性和 form-name
字段后,我们可以转到站点的已部署版本并填写表单。 提交表单并导航到 https://app.netlify.com/sites/site-name/forms
(其中 site-name
是您站点的名称)后,如果我们已成功设置表单,则我们最近的表单提交应该会出现。

重定向到确认屏幕
为了改善用户体验,我们应该添加一些逻辑,以便在表单提交时 URL 更改为 /contact/?success=true
时重定向到确认屏幕。 还可以选择在提交表单时重定向到完全不同的页面作为操作,但使用查询参数我们可以使用 Next Router 实现类似的功能。 我们可以通过创建一个新变量来实现这一点,该变量根据查询参数确定确认屏幕或表单是否可见。 使用 import { useRouter } from "next/router";
导入的 next/router 可用于检索当前的查询参数。
const router = useRouter();
const confirmationScreenVisible = router.query?.success && router.query.success === "true";
在我们的例子中,确认屏幕和表单永远不会同时可见;因此,可以使用以下语句来确定表单是否可见。
const formVisible = !confirmationScreenVisible;
为了让用户可以选择重新提交表单,我们可以在确认屏幕中添加一个按钮,通过清除查询参数来重置表单。 使用 router.replace
(而不是 router.push
)不仅更新页面,还将历史记录中的当前页面替换为不带查询参数的版本。
<button onClick={() => router.replace("/contact", undefined, { shallow: true })}> Submit Another Response </button>
然后,我们可以根据表单是否可见有条件地渲染表单,使用
{formVisible ? ContactForm : ConfirmationMessage}
综合起来,我们可以使用以下代码根据查询参数(在提交表单时更新)有条件地渲染表单
import React, { useState } from "react";
import { useRouter } from "next/router";
const ContactPage = () => {
const [submitterName, setSubmitterName] = useState("");
const router = useRouter();
const confirmationScreenVisible =
router.query?.success && router.query.success === "true";
const formVisible = !confirmationScreenVisible;
const ConfirmationMessage = (
<React.Fragment>
<p>
Thank you for submitting this form. Someone should get back to you within 24-48 hours.
</p>
<button onClick={() => router.replace("/contact", undefined, { shallow: true })}> Submit Another Response </button>
</React.Fragment>
);
const ContactForm = (/* code in first code example */);
return (
<div>
<h1>Contact Us</h1>
{formVisible ? ContactForm : ConfirmationMessage}
</div>
);
};
export default ContactPage;
添加隐藏的机器人字段
现在我们的表单核心功能正在工作,除了默认包含在所有 Netlify 表单中的 Akismet 垃圾邮件检测之外,我们还可以为表单添加其他垃圾邮件检测。 我们可以通过向表单添加 data-netlify-honeypot="bot-field"
来启用此功能。
<form
className="container"
method="POST"
name="contact-form"
action="contact/?success=true"
data-netlify="true"
data-netlify-honeypot="bot-field"
>
我们还需要创建一个新的隐藏段落,其中包含一个名为 bot-field
的标签,其中包含输入。 此字段对机器人“可见”,但对人类不可见。 当此诱骗表单字段被填写时,Netlify 会检测到机器人,然后提交会被标记为垃圾邮件。
<p hidden>
<label>
Don’t fill this out: <input name="bot-field" />
</label>
</p>
进一步自定义
- 我们可以探索 Netlify 支持的另一种垃圾邮件预防选项,方法是将 reCAPTCHA 2 添加到 Netlify 表单中。
- 我们可以更新表单以 允许上传文件,使用输入
<input type="file">
。 - 我们可以为表单提交设置通知。 这在
https://app.netlify.com/sites/[your-site-name]/settings/forms
中进行,我们可以在其中包含一个自定义主题字段(可以隐藏)以用于电子邮件通知。

完整代码
完整站点代码可在 GitHub 上获取。
附加内容
以下代码包含了我们涵盖的所有内容,以及使用姓名字段中提交的内容设置自定义主题行的逻辑。
import React, { useState } from "react";
import { useRouter } from "next/router";
const ContactPage = () => {
const [submitterName, setSubmitterName] = useState("");
const router = useRouter();
const confirmationScreenVisible =
router.query?.success && router.query.success === "true";
const formVisible = !confirmationScreenVisible;
const ConfirmationMessage = (
<React.Fragment>
<p>
Thank you for submitting this form. Someone should get back to you
within 24-48 hours.
</p>
<button onClick={() => router.replace("/contact", undefined, { shallow: true })}> Submit Another Response </button>
</React.Fragment>
);
const ContactForm = (
<form
className="container"
method="POST"
name="contact-form"
action="contact/?success=true"
data-netlify="true"
data-netlify-honeypot="bot-field"
>
<input
type="hidden"
name="subject"
value={`You've got mail from ${submitterName}`}
/>
<input type="hidden" name="form-name" value="contact-form" />
<p hidden>
<label>
Don’t fill this out: <input name="bot-field" />
</label>
</p>
<label htmlFor="name">Name *</label>
<input
id="name"
name="name"
required
onChange={(e) => setSubmitterName(e.target.value)}
type="text"
/>
<label htmlFor="company">Company *</label>
<input id="company" name="company" required type="text" />
<label htmlFor="email">E-mail Address *</label>
<input id="email" type="email" name="email" required />
<label htmlFor="message">Message *</label>
<textarea id="message" name="message" required/>
<button type="submit">Submit</button>
</form>
);
return (
<div>
<h1>Contact Us</h1>
{formVisible ? ContactForm : ConfirmationMessage}
</div>
);
};
export default ContactPage;
哇!