仿造问卷星--开发一套调查问卷设计工具(2/3)--完整流程

本章主要内容是完善index.js逻辑功能。

1,修改index.html,直接copy

html和css文件直接从源码中拷贝:

html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>问卷设计工具</title>
    <link rel="stylesheet" href="./index.css" />
  </head>
  <body class="wrapper">
    <div class="row">
      <div class="form">
        <div class="row">
          问卷ID:<br />
          <input id="qid" type="text" value="1" />
        </div>
        <div class="row">
          问卷名称:<br />
          <input id="qname" type="text" value="测试问卷" />
        </div>
        <div class="row">
          问卷题目:<br />
          <textarea name="" id="text" cols="60" rows="20">
  1. 题目1
  选项1
  选项2
  选项3
  
  2.题目2[多选题]
  选项4
  选项5
  选项6
  
  3.单行文本题
          </textarea>
        </div>
        <div class="row">
          <button id="btn">生成问卷</button>
        </div>

        <div class="row">
          JSON结果:<br />
          <pre class="json-preview" id="json-preview"></pre>
        </div>
        <div class="row">
          <button id="copy">拷贝JSON内容</button>
        </div>
      </div>
      <div class="result">
        <div class="row">
          问卷预览:<br />
          <div class="html-preview" id="html-preview"></div>
        </div>
      </div>
    </div>

    <div class="footer">Powered by
      <a href="https://webify.cloudbase.net/">CloudBase Webify</a></div>
    <script type="module" src="./index.js"></script>
  </body>
</html>

css

.form {
    
    
    float: left;
    min-height: 300px;
    padding: 20px;
  }
  .row {
    
    
    clear: both;
    margin: 5px 0;
  }
  .row::after {
    
    
    content: "";
    display: table;
    clear: both;
  }
  .result {
    
    
    float: left;
    margin-left: 20px;
  }
  .question-wrap {
    
    
    padding: 20px;
  }
  .question-wrap:hover {
    
    
    background-color: #f5f5f5;
  }
  .label {
    
    
    display: block;
    margin: 5px;
  }
  .html-preview {
    
    
    width: 500px;
    box-sizing: border-box;
    padding: 20px;
    border: solid 1px #ccc;
  }
  .json-preview {
    
    
    width: 500px;
    height: 100px;
    border: solid 1px #ccc;
    overflow: scroll;
  }
  

html结构说明:

从上到下:问卷id(输入框),问卷名称(输入框),问卷题目(文本框 存放对象数据),生成问卷(button按钮),JSON结果(文本框),拷贝JSON内容(button按钮)。

其中,用户点击 生成问卷(button按钮),右边生成一个问卷游览;并且把这套问卷的json题目展示到JSON结果文本框中,用户点击 拷贝JSON内容(button按钮),可以将JSON结果文本框中的内容拷贝到剪切板,方便粘贴到其他使用。

2,运行index后,界面如下图

在这里插入图片描述

3,在index.js中添加“生成问卷” button按钮的点击事件:

从text富文本中拿到内容并把用户输入的内容打印输出

document.getElementById("btn").addEventListener("click", function () {
    
    
  
    // 用户输入的字符串
    let text = document.getElementById("text").value;
    console.log(text);

})

打印输出结果如下:
在这里插入图片描述

对打印输出的富文本内容进行修改

4,按空行分割题目,生成数组并打印输出:

利用正则表达式,使用string.split方法,里面传一个正则表达式,将字符串进行空行分割。
在这里插入图片描述
没有文字内容,只有空内容。


//正则表达式  除了空白和换行,其他什么都没有,就是一个空行
const regexQuestionSplit = /\n\s*\n/gm;

document.getElementById("btn").addEventListener("click", function () {
    
    
  
    // 用户输入的字符串
    let text = document.getElementById("text").value;
    console.log(text);

      // 按空行分割题目
  let questionArr = text.split(regexQuestionSplit);
  console.log(questionArr);

})

分割的输出数组结果:
在这里插入图片描述

开始对每个题目进行处理,分割每一行

  let questions = [];
  // 开始对每个题目进行处理
  questionArr.forEach((q) => {
    
    
    // 分割每一行
    let rows = q.split(regexQuestionRowSplit);
    //console.log(JSON.stringify(rows));
    // 去掉空行
    rows = rows.filter((item) => item.trim() !== "");
    // console.log(JSON.stringify(rows));
        // 全部去掉前后空格
    rows = rows.reduce((acc, cur) => {
    
    
      return [...acc, cur.trim()];
    }, []);
    console.log(JSON.stringify(rows));

  })

输出结果如下:
在这里插入图片描述

5,对填空题,单选题和多选题分别利用正则表达式来处理:

import {
    
     prettyPrintJson } from "pretty-print-json";
import copy from "copy-to-clipboard";
import gotpl from "gotpl";

const regexQuestionSplit = /\n\s*\n/gm;
const regexQuestionRowSplit = /\n/gm;
const regexTitle1 = /(?<index>\d+)[.][\s]*(?<title>[^\n]*)$/;
const retexTitle2 =
  /(?<index>\d+)[.][\s]*(?<title>[^\[]*)[\[](?<type>\W+)[\]]$/;
let resultObj = {
    
    
  id: 0,
  name: "",
  questions: [],
};
let resultJson = "";

const tpl = `
<div class="question">
  <div class="row">
    问卷ID:<%= id %>
  </div>
  <div class="row">
    问卷名称:<%= name %>
  </div>
  <% for(var i=0, l=questions.length; i<l; ++i){
    
     %>
    <% var item = questions[i]; %>
    <div class="question-wrap">
      <div class="question-title"><%= item.id %>. <%= item.title %><%=item.question_type_text %></div>
      <% if(item.question_type === 'input'){
    
     %>
        <div class="input">
          <input type="text" name="<%= item.id %>" />
        </div>
      <% }else if(item.question_type === 'radio'){
    
     %>
        <div class="radio">
          <% for(var j=0, k=item.options.length; j<k; ++j){
    
     %>
            <label class="label">
              <input type="radio" name="<%= item.id %>" value="<%= item.options[j].option_id %>" />
              <%= item.options[j].option_id %>.
              <%= item.options[j].option_value %>
            </label>
          <% } %>
        </div>
      <% }else if(item.question_type === 'checkbox'){
    
     %>
        <div class="checkbox">
          <% for(var j=0, k=item.options.length; j<k; ++j){
    
     %>
            <label class="label">
              <input type="checkbox" name="<%= item.id %>" value="<%= item.options[j].option_id %>" />
              <%= item.options[j].option_id %>.
              <%= item.options[j].option_value %>
            </label>
          <% } %>
        </div>
      <% } %>
    </div>
  <% } %>
</div>
`;

const alphabet = [
  "A",
  "B",
  "C",
  "D",
  "E",
  "F",
  "G",
  "H",
  "I",
  "J",
  "K",
  "L",
  "M",
  "N",
  "O",
  "P",
  "Q",
  "R",
  "S",
  "T",
  "U",
  "V",
  "W",
  "X",
  "Y",
  "Z",
];
const type_map = {
    
    
  填空题: "input",
  单选题: "radio",
  多选题: "checkbox",
};
function getQuestionType(questionType) {
    
    
  return type_map[questionType] || "类型错误";
}
function formatQuestion(index, title, typeText, options = null) {
    
    
  // console.log(index, title, questionType);
  const questionType = getQuestionType(typeText);
  let question = {
    
    
    id: +index,
    title: title,
    question_type: questionType,
    question_type_text: typeText,
  };
  // console.log(options);
  if (options && options.length) {
    
    
    let tmpOptions = [];
    options.forEach((item, index) => {
    
    
      tmpOptions.push({
    
    
        option_id: alphabet[index],
        option_value: item,
      });
    });
    question.options = tmpOptions;
  }
  return question;
}

document.getElementById("btn").addEventListener("click", function () {
    
    
  resultObj.id = +document.getElementById("qid").value.trim();
  resultObj.name = document.getElementById("qname").value.trim();

  // 用户输入的字符串
  let text = document.getElementById("text").value;
  // console.log(text);

  // 按空行分割题目
  let questionArr = text.split(regexQuestionSplit);
  // console.log(questionArr);

  let questions = [];
  // 开始对每个题目进行处理
  questionArr.forEach((q) => {
    
    
    // 分割每一行
    let rows = q.split(regexQuestionRowSplit);
    // console.log(JSON.stringify(rows));

    // 去掉空行
    rows = rows.filter((item) => item.trim() !== "");
    // console.log(JSON.stringify(rows));

    // 全部去掉前后空格
    rows = rows.reduce((acc, cur) => {
    
    
      return [...acc, cur.trim()];
    }, []);
    // console.log(JSON.stringify(rows));

    // 如果是单行,是填空题
    if (rows.length === 1) {
    
    
      if (regexTitle1.test(rows[0])) {
    
    
        let matches = rows[0].match(regexTitle1);
        // console.log(matches);
        let {
    
     index, title } = matches.groups;
        questions.push(formatQuestion(index, title, "填空题"));
      }
    }
    // console.log(questions);

    // 多行,可能是单选或多选
    if (rows.length > 1) {
    
    
      // 第一行是标题,其他行是选项
      let [titleRow, ...options] = rows;
      // console.log("titleRow", titleRow);
      // console.log("options", options);

      // 先验证带题目类型的格式
      if (retexTitle2.test(titleRow)) {
    
    
        let matches = titleRow.match(retexTitle2);
        //  console.log(matches)
        let {
    
     index, title, type } = matches.groups;
        questions.push(formatQuestion(index, title, type, options));
      } else if (regexTitle1.test(titleRow)) {
    
    
        // 没有设置类型的,当成单选题
        let matches = titleRow.match(regexTitle1);
        let {
    
     index, title } = matches.groups;
        console.log(index, title, options);
        questions.push(formatQuestion(index, title, "单选题", options));
      }
      // console.log(questions);
    }
  });

  resultObj.questions = questions;
  resultJson = JSON.stringify(resultObj);
  console.log(resultObj);
  document.getElementById("json-preview").innerHTML =
    prettyPrintJson.toHtml(resultObj);

  document.getElementById("html-preview").innerHTML = gotpl.render(
    tpl,
    resultObj
  );
});

document.getElementById("copy").onclick = () => {
    
    
  copy(resultJson);
  alert("已复制到剪贴板");
};

6,输出最终结果:

在这里插入图片描述

输出的json数据如下:

[
    {
    
    
        "id": 1,
        "title": "题目1",
        "question_type": "radio",
        "question_type_text": "单选题",
        "options": [
            {
    
    
                "option_id": "A",
                "option_value": "选项1"
            },
            {
    
    
                "option_id": "B",
                "option_value": "选项2"
            },
            {
    
    
                "option_id": "C",
                "option_value": "选项3"
            }
        ]
    },
    {
    
    
        "id": 2,
        "title": "题目2",
        "question_type": "checkbox",
        "question_type_text": "多选题",
        "options": [
            {
    
    
                "option_id": "A",
                "option_value": "选项4"
            },
            {
    
    
                "option_id": "B",
                "option_value": "选项5"
            },
            {
    
    
                "option_id": "C",
                "option_value": "选项6"
            }
        ]
    },
    {
    
    
        "id": 3,
        "title": "单行文本题",
        "question_type": "input",
        "question_type_text": "填空题"
    },
    {
    
    
        "id": 4,
        "title": "题目2",
        "question_type": "checkbox",
        "question_type_text": "多选题",
        "options": [
            {
    
    
                "option_id": "A",
                "option_value": "选项4"
            },
            {
    
    
                "option_id": "B",
                "option_value": "选项5"
            },
            {
    
    
                "option_id": "C",
                "option_value": "选项6"
            }
        ]
    }
]

猜你喜欢

转载自blog.csdn.net/weixin_43025151/article/details/129961946