使用 HTML + JavaScript 实现简易问卷调查表

在项目开发中,问卷调查是一种常见的用户数据收集方式。本文将介绍如何使用 HTML、CSS 和 JavaScript 构建一个简易的问卷调查页面。

效果演示

image-20250525223506662

在这里插入图片描述

项目概述

本项目是一个前端静态页面,包含以下主要功能:

  • 动态生成问卷题目
  • 支持多种题型:单选、多选、文本输入、评分
  • 表单验证机制
  • 提交后显示结果
  • 简洁美观的 UI 设计

页面结构与样式

创建 HTML 结构
<div class="survey-container">
    <h1>产品使用情况调查</h1>
    <div id="surveyQuestions"></div>
    <button onclick="submitSurvey()">提交问卷</button>
    <div id="results" class="results"></div>
</div>
设计 CSS 样式
.survey-container {
    max-width: 800px;
    margin: 20px auto;
    padding: 20px;
    background: #f8f9fa;
    border-radius: 8px;
    box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
h1 {
    text-align: center;
}
.question {
    margin-bottom: 25px;
    padding: 15px;
    background: white;
    border-radius: 5px;
    border-left: 4px solid #007bff;
}
.question-title {
    font-size: 1.1em;
    margin-bottom: 15px;
    color: #333;
}
.options-group {
    margin: 10px 0;
}
.option-item {
    margin: 8px 0;
    display: flex;
    align-items: center;
}
input[type="radio"],
input[type="checkbox"] {
    margin-right: 8px;
}
label {
    cursor: pointer;
    user-select: none;
}
textarea {
    width: 100%;
    padding: 8px;
    border: 1px solid #ddd;
    border-radius: 4px;
    resize: vertical;
}
button {
    display: block;
    margin: 0 auto;
    background: #28a745;
    color: white;
    padding: 12px 25px;
    border: none;
    border-radius: 5px;
    cursor: pointer;
    font-size: 1em;
}
.error-msg {
    color: #dc3545;
    font-size: 0.9em;
    margin-top: 5px;
    display: none;
}
.results {
    display: none;
    margin-top: 30px;
    padding: 20px;
    background: #e9ecef;
    border-radius: 5px;
}

定义基础数据

所有问题都定义在一个 surveyConfig 数组中,每道题可以配置类型、问题描述、是否必填等属性。

const surveyConfig = [
    {
        type: "radio",
        question: "1. 您的年龄范围",
        name: "age",
        required: true,
        options: [
            { value: "18-25", label: "18-25岁" },
            { value: "26-35", label: "26-35岁" },
            { value: "36-45", label: "36-45岁" },
            { value: "46+", label: "46岁及以上" }
        ]
    },
    // ...
];

交互功能

动态生成问卷

通过遍历 surveyConfig,动态创建 DOM 元素并插入到页面中,支持不同类型的题目。

function initSurvey() {
    const container = document.getElementById('surveyQuestions');

    surveyConfig.forEach((question, index) => {
        const questionDiv = document.createElement('div');
        questionDiv.className = 'question';
        questionDiv.innerHTML = `<div class="question-title">${question.question}</div><div class="error-msg">请回答此题</div>`;

        // 添加输入控件
        const inputGroup = document.createElement('div');
        inputGroup.className = 'options-group';

        switch(question.type) {
            case 'radio':
            case 'checkbox':
                question.options.forEach(option => {
                    const optionId = `${question.name}_${option.value}`; // 生成唯一ID
                    inputGroup.innerHTML += `<div class="option-item">
<input type="${question.type}" id="${optionId}" name="${question.name}" value="${option.value}">
<label for="${optionId}">${option.label}</label>
</div>`;
                });
                break;
            // ...
        }

        questionDiv.appendChild(inputGroup);
        container.appendChild(questionDiv);
    });
}
表单验证

验证失败时会高亮问题区域,并显示错误信息。

function validateForm() {
    let isValid = true;
    surveyConfig.forEach((question, index) => {
        const questionDiv = document.getElementsByClassName('question')[index];
        const errorMsg = questionDiv.querySelector('.error-msg');

        // 重置错误状态
        errorMsg.style.display = 'none';
        questionDiv.style.borderColor = '#007bff';

        if(question.required) {
            let isAnswered = false;

            switch(question.type) {
                case 'radio':
                case 'rating':
                    isAnswered = !!questionDiv.querySelector(`input[name="${question.name}"]:checked`);
                    break;
                // ...
            }

            if(!isAnswered) {
                errorMsg.style.display = 'block';
                questionDiv.style.borderColor = '#dc3545';
                isValid = false;
            }
        }
    });
    return isValid;
}
数据收集

从页面中提取每个问题的答案,返回一个 JSON 对象,便于后续处理或提交。

function collectData() {
    const result = {};

    surveyConfig.forEach(question => {
        switch(question.type) {
            case 'radio':
            case 'rating':
                const radio = document.querySelector(`input[name="${question.name}"]:checked`);
                result[question.name] = radio ? radio.value : null;
                break;
            // ...
        }
    });

    return result;
}
提交问卷

表单验证 validateForm() 通过后调用 collectData() 获取数据,展示结果,可替换为请求发送至服务器。

function submitSurvey() {
    if(!validateForm()) return;
    const formData = collectData();
    // 显示结果
    const resultsDiv = document.getElementById('results');
    resultsDiv.style.display = 'block';
    resultsDiv.innerHTML = `<h3>提交成功,感谢您的参与!</h3>
                <p>您的回答:</p>
                <pre>${JSON.stringify(formData, null, 2)}</pre>`;
    // 清空表单
    document.querySelectorAll('input, textarea').forEach(el => {
        if(el.type === 'radio' || el.type === 'checkbox') {
            el.checked = false;
        } else {
            el.value = '';
        }
    });
}

扩展建议

虽然这是一个简单的问卷系统,但仍具备良好的扩展性:

  • 后端集成:通过接口获取表单配置信息 surveyConfig,将 submitSurvey() 中的数据通过请求发送至服务端
  • 更多题型:支持下拉选择、文件上传等

完整代码

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>简易问卷调查</title>
    <style>
        .survey-container {
            max-width: 800px;
            margin: 20px auto;
            padding: 20px;
            background: #f8f9fa;
            border-radius: 8px;
            box-shadow: 0 2px 4px rgba(0,0,0,0.1);
        }
        h1 {
            text-align: center;
        }
        .question {
            margin-bottom: 25px;
            padding: 15px;
            background: white;
            border-radius: 5px;
            border-left: 4px solid #007bff;
        }
        .question-title {
            font-size: 1.1em;
            margin-bottom: 15px;
            color: #333;
        }
        .options-group {
            margin: 10px 0;
        }
        .option-item {
            margin: 8px 0;
            display: flex;
            align-items: center;
        }
        input[type="radio"],
        input[type="checkbox"] {
            margin-right: 8px;
        }
        label {
            cursor: pointer;
            user-select: none;
        }
        textarea {
            width: 100%;
            padding: 8px;
            border: 1px solid #ddd;
            border-radius: 4px;
            resize: vertical;
        }
        button {
            display: block;
            margin: 0 auto;
            background: #28a745;
            color: white;
            padding: 12px 25px;
            border: none;
            border-radius: 5px;
            cursor: pointer;
            font-size: 1em;
        }
        .error-msg {
            color: #dc3545;
            font-size: 0.9em;
            margin-top: 5px;
            display: none;
        }
        .results {
            display: none;
            margin-top: 30px;
            padding: 20px;
            background: #e9ecef;
            border-radius: 5px;
        }
    </style>
</head>
<body>
<div class="survey-container">
    <h1>产品使用情况调查</h1>
    <div id="surveyQuestions"></div>
    <button onclick="submitSurvey()">提交问卷</button>
    <div id="results" class="results"></div>
</div>

<script>
    // 问卷配置
    const surveyConfig = [
        {
            type: "radio",
            question: "1. 您的年龄范围",
            name: "age",
            required: true,
            options: [
                { value: "18-25", label: "18-25岁" },
                { value: "26-35", label: "26-35岁" },
                { value: "36-45", label: "36-45岁" },
                { value: "46+", label: "46岁及以上" }
            ]
        },
        {
            type: "checkbox",
            question: "2. 您使用我们产品的场景(多选)",
            name: "scenarios",
            required: true,
            options: [
                { value: "work", label: "工作" },
                { value: "study", label: "学习" },
                { value: "entertainment", label: "娱乐" },
                { value: "other", label: "其他" }
            ]
        },
        {
            type: "rating",
            question: "3. 请为产品满意度打分(1-5分)",
            name: "satisfaction",
            required: true
        },
        {
            type: "textarea",
            question: "4. 请提供您的宝贵意见",
            name: "suggestion",
            required: true,
            placeholder: "请输入意见"
        },
    ];

    // 初始化问卷
    function initSurvey() {
        const container = document.getElementById('surveyQuestions');

        surveyConfig.forEach((question, index) => {
            const questionDiv = document.createElement('div');
            questionDiv.className = 'question';
            questionDiv.innerHTML = `<div class="question-title">${question.question}</div><div class="error-msg">请回答此题</div>`;

            // 添加输入控件
            const inputGroup = document.createElement('div');
            inputGroup.className = 'options-group';

            switch(question.type) {
                case 'radio':
                case 'checkbox':
                    question.options.forEach(option => {
                        const optionId = `${question.name}_${option.value}`; // 生成唯一ID
                        inputGroup.innerHTML += `<div class="option-item">
                                    <input type="${question.type}" id="${optionId}" name="${question.name}" value="${option.value}">
                                    <label for="${optionId}">${option.label}</label>
                                </div>`;
                    });
                    break;
                case 'textarea':
                    inputGroup.innerHTML = `
                            <textarea name="${question.name}" placeholder="${question.placeholder || ''}" rows="3"></textarea>
                        `;
                    break;

                case 'rating':
                    for(let i=1; i<=5; i++) {
                        const optionId = `${question.name}_${i}`; // 生成唯一ID
                        inputGroup.innerHTML += `<div class="option-item">
                                    <input type="radio" id="${optionId}" name="${question.name}" value="${i}">
                                    <label for="${optionId}">${i} 分</label>
                                </div>`;
                    }
                    break;
            }

            questionDiv.appendChild(inputGroup);
            container.appendChild(questionDiv);
        });
    }

    // 验证问卷
    function validateForm() {
        let isValid = true;
        surveyConfig.forEach((question, index) => {
            const questionDiv = document.getElementsByClassName('question')[index];
            const errorMsg = questionDiv.querySelector('.error-msg');

            // 重置错误状态
            errorMsg.style.display = 'none';
            questionDiv.style.borderColor = '#007bff';

            if(question.required) {
                let isAnswered = false;

                switch(question.type) {
                    case 'radio':
                    case 'rating':
                        isAnswered = !!questionDiv.querySelector(`input[name="${question.name}"]:checked`);
                        break;

                    case 'checkbox':
                        isAnswered = questionDiv.querySelectorAll(`input[name="${question.name}"]:checked`).length > 0;
                        break;

                    case 'textarea':
                        const textValue = questionDiv.querySelector('textarea').value.trim();
                        isAnswered = textValue.length > 0;
                        break;
                }

                if(!isAnswered) {
                    errorMsg.style.display = 'block';
                    questionDiv.style.borderColor = '#dc3545';
                    isValid = false;
                }
            }
        });

        return isValid;
    }

    // 收集数据
    function collectData() {
        const result = {};

        surveyConfig.forEach(question => {
            switch(question.type) {
                case 'radio':
                case 'rating':
                    const radio = document.querySelector(`input[name="${question.name}"]:checked`);
                    result[question.name] = radio ? radio.value : null;
                    break;

                case 'checkbox':
                    const checkboxes = [...document.querySelectorAll(`input[name="${question.name}"]:checked`)];
                    result[question.name] = checkboxes.map(cb => cb.value);
                    break;

                case 'text':
                    result[question.name] = document.querySelector(`textarea[name="${question.name}"]`).value.trim();
                    break;
            }
        });

        return result;
    }

    // 提交问卷
    function submitSurvey() {
        if(!validateForm()) return;
        const formData = collectData();
        // 显示结果(实际使用中可替换为AJAX请求)
        const resultsDiv = document.getElementById('results');
        resultsDiv.style.display = 'block';
        resultsDiv.innerHTML = `<h3>提交成功,感谢您的参与!</h3>
                <p>您的回答:</p>
                <pre>${JSON.stringify(formData, null, 2)}</pre>`;
        // 清空表单
        document.querySelectorAll('input, textarea').forEach(el => {
            if(el.type === 'radio' || el.type === 'checkbox') {
                el.checked = false;
            } else {
                el.value = '';
            }
        });
    }

    // 初始化
    initSurvey();
</script>
</body>
</html>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值