如何使用 Next.js 和 Netlify 创建联系表单

Avatar of Monica Powell
Monica Powell

DigitalOcean 为您旅程的每个阶段提供云产品。 立即开始使用 200 美元的免费额度!

我们将使用 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;