如何通过全局变量更新SurveyJS JSON配置并实现迭代式动态问卷
迭代式问卷的结构修复方案
先修导致功能直接崩溃的硬错误
这些问题不解决,再怎么调整结构都是白搭:
start函数里的while (count > 20);末尾带分号,循环体是空内容,只要count初始值大于20直接触发死循环,卡到浏览器崩溃。这就是你之前把系统逻辑全塞到start里之后,整个问卷直接失效的核心原因——这行本来就没写对,直接删掉就行,哪怕要做展示判断写个if都比这行的逻辑靠谱。document.getElementById("streetscape").style="display:visible";这行根本执行不了,CSS规范里display属性没有visible这个合法值,执行时控制台直接抛类型错误,后续DOM操作会全部中断。要么把属性改成display: block/inline-block,要么把样式属性换成visibility: visible。- 你现在count的自增逻辑是分叉的:
onComplete回调里先手动执行window.count++,再调用update(),而update()里第一行的knxer()本身就包含count自增逻辑,等于每轮count会多涨1次,和后续JSON里存的count值完全对不上,迭代越久偏差越大。
解决动态变量没法同步到问卷结果的核心逻辑错位
你之前设计的问题根源在于:你以为Survey模型会实时追踪全局变量的变化,实际上你只在页面初始化时跑了一次jsoner(),把当时的JSON快照传给了new Survey.Model(),后续哪怕全局变量更新了,已经实例化的Survey根本感知不到这些变化,自然没法把新值带到提交结果里。
可以按下面的结构重构,不需要重新写整个逻辑:
- 把原来的
jsoner()改造成纯函数,不要往全局变量上挂生成的JSON,每次调用时先算完所有动态值,再返回完整的问卷schema:function buildSurveySchema() { // 所有动态值先在函数内计算完成,再拼到schema里 const currentPID = usernamer(); const currentKey = keynamer(); const currentCount = knxer(); const currentMapLink = mapilinker(); const currentImg = imgur(); return { pages: [ { name: "page1", elements: [ // 隐藏字段在生成schema时直接把值嵌到defaultValue里 { type: "text", name: "UID", visible: false, title: "USERID", defaultValue: currentPID }, { type: "text", name: "Keyn", visible: false, title: "Key", defaultValue: currentKey }, { type: "text", name: "CNT", visible: false, title: "TIME", defaultValue: currentCount }, // 动态图片、动态链接的题目也在这一步直接替换值 { type: "image", name: "scene", imageLink: currentImg } // ... 原有问卷题目 ] } ] } } - Survey实例只需要新建一次,不要每次迭代重新new,直接替换模型的schema就行:
// 全局只初始化一次Survey实例 window.survey = new Survey.Model(); // 绑定页面渲染逻辑只做一次 $("#surveyElement").Survey({ model: survey }); - 调整
onComplete的执行顺序,不要把变量更新放到结果生成之前:- 提交完成后先取出用户作答结果,手动拼接全局元数据——比起靠隐藏字段存值,手动拼payload要靠谱得多,就算后面调用
survey.clear()清掉了题目值,你自己拼的元数据也不会丢 - 再执行下一轮的迭代变量计算
- 最后调用Survey提供的
setProperties方法替换成新一轮的问卷schema,清空状态重新渲染
survey.onComplete.add((result) => { // 自定义提交结果,元数据直接手动拼,不需要依赖Survey字段 const submitPayload = { ...result.data, meta: { pid: username, count: currentGlobalCount, // 取提交瞬间的全局实时值 keyn: currentGlobalKeyName } } // 把结果渲染到页面、存储到后端 document.querySelector('#surveyResult').textContent = JSON.stringify(submitPayload, null, 3); // 存完结果再计算下一轮的迭代值 currentGlobalCount++; // 替换成新一轮的问卷schema,新的动态值会直接嵌到schema里 survey.setProperties(buildSurveySchema()); survey.clear(); survey.render(); }) - 提交完成后先取出用户作答结果,手动拼接全局元数据——比起靠隐藏字段存值,手动拼payload要靠谱得多,就算后面调用
调整start函数的职责边界
你之前把整个问卷生成、全局逻辑全塞到start里才导致功能崩溃,其实只需要把和登录弹窗、用户输入绑定的逻辑放到start里就行,全局变量在模块顶层声明,所有函数都能正常访问:
// 模块顶层声明全局变量,避免函数作用域导致的取值失效 let username = ""; let count = 0; let keyname = ""; function start() { // start只做登录相关的DOM操作 username = document.getElementById("user_PID").value; alert("your PID is " + username); modal.style.display = "none"; document.getElementById("surveyElement").style.display = "inline-block"; document.getElementById("surveyElement").style.width = "100%"; document.getElementById("streetscape").style.display = "block"; document.getElementById("btn1").style.display = "none"; // 登录完成后渲染第一版问卷就行 survey.setProperties(buildSurveySchema()); }
额外踩坑提醒:你代码里给defaultValue赋值时写的
defaultValue: (PID2)这种多余的括号完全可以去掉,另外如果调用survey.clear()时,非必填的隐藏字段defaultValue会被重置,所以根本不需要纠结隐藏字段的同步问题,自定义拼结果才是最可控的方案。
内容的提问来源于stack exchange,提问作者StupidQuestionGuy
相关产品推荐
相关产品推荐

