如何通过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的新应用路由器(而非旧的文件路由器)。
设置完成后,运行:
这将启动开发服务器,文件更改时会自动更新。保持运行以便添加页面时无需重新构建。
设置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提供众多开箱即用的优势,尽管代码量不多,但所构建的系统能够轻松扩展至任意数量的表单。
感谢阅读本指南。您可以查看完整仓库或体验已部署的系统版本。