使用Next.js与SurveyJS构建极速调查系统

本文详细介绍了如何利用Next.js框架和SurveyJS库构建高性能的调查问卷系统,包括表单创建、动态页面生成、结果可视化及API集成,实现SEO友好且扩展性强的全栈应用。

如何通过Next.js和SurveyJS构建极速调查系统

在本指南中,我们将逐步构建一个能够创建新调查、分享调查并分析结果的网站。该网站将基于Next.js的最新功能,实现极速加载和SEO友好,同时借助SurveyJS轻松处理调查表单。

本文假设您已了解React和Next.js的基础知识,但会详细讲解每个组件和页面的构建过程。您可以跟随文章获取全部代码,或直接使用示例仓库。还可以查看我已部署的最终版本网站。

Next.js与SurveyJS简介

Next.js是一个基于React的框架,帮助您完全在React中构建全栈网站。它处理所有打包工作,并提供强大的API来决定如何渲染每个页面以实现极速性能。本文将确保所有页面在构建时渲染,从而轻松生成供Google索引的站点地图,这对SEO至关重要。

SurveyJS是一个开源表单管理工具,使您能够创建、分享和分析调查及表单。它提供React API,我们将与Next.js结合使用来构建调查管理系统。

设置Next.js

首先,设置Next.js应用。Next.js提供CLI工具,可根据您的偏好快速创建基础应用。

确保已安装npx,然后运行以下命令:

1
npx create-next-app@latest

运行create-next-app后,它会询问一系列关于项目的问题。大多数问题基于个人偏好,可随意回答。本文使用纯JavaScript(而非TypeScript)和Next.js的新应用路由器(而非旧的文件路由器)。

设置完成后,运行:

1
yarn run dev

这将启动开发服务器,文件更改时会自动更新。保持运行以便添加页面时无需重新构建。

设置SurveyJS

安装所有相关依赖:

1
yarn add survey-analytics survey-core survey-creator-core survey-creator-react survey-react-ui

设置表单创建器

首先添加表单创建器页面,路径为/creator。创建文件/creator/page.js:

1
2
3
4
5
6
7
export const metadata = {
  title: "Survey Creator",
};

export default function Page() {
  return <Creator />;
}

metadata对象用于Next.js的SEO元标签。Creator组件使用SurveyJS API:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
"use client";

import { useEffect, useState } from "react";
import { SurveyCreatorComponent, SurveyCreator } from "survey-creator-react";

export default function Creator() {
  let [creator, setCreator] = useState();

  useEffect(() => {
    const newCreator = new SurveyCreator({
      showLogicTab: true,
      showTranslationTab: true,
    });
    setCreator(newCreator);
  }, []);

  return <div>{creator && <SurveyCreatorComponent creator={creator} />}</div>;
}

use client指令确保组件在客户端运行。useEffect创建SurveyCreator实例并配置选项。渲染SurveyCreatorComponent并传递creator对象。

访问/creator即可使用创建器功能。

创建表单查看页面

接下来创建动态页面以查看已构建的表单。使用Next.js动态路由,创建文件/app/form/[slug]/page.js,路径为/form/form-slug。

首先定义generateStaticParams:

1
2
3
export async function generateStaticParams() {
  return surveys.map((x) => ({ slug: x.slug }));
}

假设已设置导出调查列表的文件(包含slug和调查对象)。添加新调查只需向数组添加新条目。

然后定义generateMetadata:

1
2
3
4
5
6
7
8
export async function generateMetadata({ params }) {
  const survey = surveys.find((x) => x.slug === params.slug);

  return {
    title: survey.survey.title,
    description: survey.survey.description,
  };
}

该函数根据slug查找调查对象,并返回标题和描述用于元数据。

最后定义页面组件:

1
2
3
4
5
6
7
8
9
export default function Page({ params: { slug } }) {
  const survey = surveys.find((x) => x.slug === slug);

  return (
    <div>
      <SurveyComponent surveyData={survey.survey} />
    </div>
  );
}

SurveyComponent定义如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
"use client";

import { useCallback } from "react";
import { Model } from "survey-core";
import { Survey } from "survey-react-ui";

export default function SurveyComponent({ surveyData }) {
  const model = new Model(surveyData);

  const alertResults = useCallback(async (sender) => {
    fetch("/api/submit", {
      method: "POST",
      headers: {
        "Content-Type": "application/json;charset=UTF-8",
      },
      body: JSON.stringify({ result: sender.data }),
    });
  }, []);

  model.onComplete.add(alertResults);

  return <Survey model={model} />;
}

use client指令确保客户端运行。创建SurveyJS模型并传递给Survey组件。设置onComplete函数,将数据发送到/api/submit。

创建API端点文件/api/submit/route.js:

1
2
3
4
5
6
7
export async function POST(request) {
  const res = await request.json();

  console.log(res);

  return Response.json({ message: "Done" });
}

POST函数接收数据并记录到控制台。此处可添加数据库保存或验证逻辑。

创建结果查看页面

创建动态页面以查看调查结果,路径为/results/[slug]/page.js。

定义generateStaticParams,过滤无结果的调查:

1
2
3
4
5
export async function generateStaticParams() {
  return surveys
    .filter((x) => x.results.length > 0)
    .map((x) => ({ slug: x.slug }));
}

页面组件与之前类似,但渲染Results组件:

1
2
3
4
5
6
7
8
9
export default function Page({ params: { slug } }) {
  const survey = surveys.find((x) => x.slug === slug);

  return (
    <div>
      <Results surveyData={survey} />
    </div>
  );
}

Results组件使用survey-analytics包:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
"use client";

import { useEffect } from "react";
import { Model } from "survey-core";

export default function Results({ surveyData }) {
  useEffect(() => {
    (async () => {
      const survey = new Model(surveyData.survey);

      const { VisualizationPanel } = await import("survey-analytics");

      const currentPanel = new VisualizationPanel(
        survey.getAllQuestions(),
        surveyData.results,
        {
          allowHideQuestions: false,
        }
      );

      currentPanel.render("surveyVizPanel");

      return () => {
        const panelElement = document.getElementById("surveyVizPanel");

        if (panelElement) {
          panelElement.innerHTML = "";
        }
      };
    })();
  }, [surveyData]);

  return (
    <div>
      <div id="surveyVizPanel" />
    </div>
  );
}

useEffect设置图表面板,动态导入survey-analytics包以避免构建时错误。创建可视化对象并配置选项,渲染到指定DOM元素。清理函数确保元素清空。

进一步工作

本文为您提供了将SurveyJS集成到Next.js应用的基础。要实现全功能系统,可添加认证系统以确保只有验证用户能访问不同部分,并集成数据源以创建新表单和收集用户结果。Next.js和SurveyJS使这些添加变得简单。

结论

本指南展示了如何在Next.js中使用SurveyJS构建全面的调查管理系统。Next.js提供众多开箱即用的优势,尽管代码量不多,但所构建的系统能够轻松扩展至任意数量的表单。

感谢阅读本指南。您可以查看完整仓库或体验已部署的系统版本。

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计