基于Web表单单选按钮选择显示结果Div
实现目标
简单来说,所需的是一个包含单选按钮和结果的简单表单,这些结果应该与单选结果的组合匹配。根据问题,问题应该易于维护和更改,而不必总是接触脚本或其初始逻辑。
这就要求将问题和逻辑外包 - 使其与DOM分离。
如何实现?
简要提到并且在问题标签中进一步可见的是php和ajax。鉴于可能完全希望外包问题并通过ajax从php获取它们。另外一个投票支持外包。
需要什么才能实现?
- 是否需要任何框架和/或库?不一定,但可能有用
- 我们需要一直在DOM中拥有所有问题和答案吗?不一定
为了简洁起见,让我们采取下面的(但请注意,我正在寻找相对可扩展的建议,因为我的Web表单每个具有7个问题和5个答案。而且我有5个结果divs)
- 我建议即兴创建DOM,因为截至目前还没有必要一直保持它,并且它使HTML文件本身看起来更加简洁整洁。
- 此外,可以将布局、结构、逻辑和数据分离,最终使您能够通过更改一个文件来更改答案和问题。
- 使用这种方法,您可以创建具有不同问题的更多表单,但使用相同的代码。
- 如果您尚未使用任何库/框架,则不要添加一个只是为了此脚本。
结论
为了使其易于维护,问题和答案将被外包到一个json文件中(此处为JSON.js)。鉴于此,还可以通过php或任何web服务检索它们和/或将其存储在数据库中。此外,提供了创建多个表单的可能性,其中每个表单都使用相同的代码,但问题不同。
这里提供了可用的Fiddle
代码
<html>
<head>
<!-- optional styles -->
<style>
#Container{
left: 50%;
position: absolute;
text-align: center;
top: 50%;
transform: translate(-50%, -50%);
}
</style>
<script>
//This is out simple AJAX routine to not overload it by any framework.
//If you are already using jQuery, just use $.get()
;var AJAX = {
getXmlDoc: function(){return ((window.XMLHttpRequest) ? new XMLHttpRequest() : new ActiveXObject("Microsoft.XMLHTTP"))},
//u:=url, f:=callback, c:=any param to pass to callback
Get: function(u, f, c){
var tDoc = this.getXmlDoc();
tDoc.open('GET', u, true);
tDoc.onreadystatechange = function(){
if (tDoc.readyState === XMLHttpRequest.DONE && tDoc.status === 200) f(tDoc, c);
};
tDoc.send();
}
};
//This is going to be the namespace holding our functionality.
//In the end one should outsource this to a script file, yet we leave it here in the example for a better overview.
;var Quiz = {
mContainer: null, //In this container the quiz gets created in
mCurrent: null, //Stores the current displayed question
mJSON: null, //In here we are going to store the JSON result
//Handling logical errors, like missing data or json
_Error: function(m){
console.log(m)
},
//The event called on the radio change event
//e:=element
_onChange: function(e){
if (e && this.mJSON.questions[this.mCurrent]){
//We are going to those the result of this question in the JSON
this.mJSON.questions[this.mCurrent].value = e.value;
//If the question is not the last, we are going to display the next one
if (this.mCurrent < this.mJSON.questions.length - 1){
this.hideQuestions();
this.showQuestion(this.mCurrent + 1)
}
else{
//Else we are going to show the result
this.hideQuestions();
this.showResult()
}
}
else this._Error('_onChange(): Invalid parameters')
},
//The function to initialise our quiz.
//We are going to grab the json data and analyse it.
//c:=container element || document.body, l:=link || 'JSON.js'
Init: function(c, l){
this.mContainer = (c || document.body);
var tL = (l || 'JSON.js');
AJAX.Get(tL, function(r, l){
Quiz.mJSON = JSON.parse(r.response);
if (Quiz.mJSON && Quiz.mJSON.questions)
Quiz.showQuestion(0)
else
Quiz._Error('Init(): No questions found with "' + l + '"')
}, tL)
},
//Hiding the previously asked questions (remove from dom)
hideQuestions: function(){
while(this.mContainer.firstChild) this.mContainer.removeChild(this.mContainer.firstChild)
},
//Going to show the result according to the asked questions
showResult: function(){
var tValues = []; //Storing our answers
for(var i=0, j=this.mJSON.questions.length; i<j; i++)
if (this.mJSON.questions[i].value) tValues.push(this.mJSON.questions[i].value)
//Going to store the result text
var tResult = 'No match for ' + tValues.join(',');
//Looping through all requirements to get a match
for(var i=0, j=this.mJSON.answers.length; i<j; i++){
//The requirements which need to match the values
var tR = this.mJSON.answers[i].requirement;
//For this we filter all the elements which do not match the requirements
var tF = tValues.filter(function(e){return tR.indexOf(e) === -1})
//If that list is empty, all elements matched and we can stop
if (!tF || tF.length === 0){
tResult = this.mJSON.answers[i].message;
break;
}
}
//Now we are going to dislpay the result
var tH = document.createElement('h1');
tH.innerHTML = tResult;
this.mContainer.appendChild(tH)
},
//This creates and shows a question of our question array
//i:=JSON.questions array index
showQuestion: function(i){
if (i >= 0 && i<this.mJSON.questions.length){
this.mCurrent = i;
var tQ = this.mJSON.questions[i];
var tN = Object.getOwnPropertyNames(tQ)[0]; //The property name is going to become the radio group name
//We are going to create a title (h1) and multiple radios (input & label) for each question
var tF = document.createDocumentFragment();
//Creating the header
var tH = document.createElement('h1');
tH.innerHTML = tQ.label;
tF.appendChild(tH);
//Creating the questions
for(var i=0, j=tQ[tN].length; i<j; i++){
var tR = document.createElement('input');
tR.type = 'radio';
tR.value = tQ[tN][i];
tR.name = tN;
tR.onchange = function(){Quiz._onChange(this)};
tF.appendChild(tR);
var tL = document.createElement('label');
tL.for = tR.name;
tL.innerHTML = tR.value;
tF.appendChild(tL);
}
//Now we are going to assign it to the dom.
this.mContainer.appendChild(tF)
}
else{
this.mCurrent = null;
this._Error('showQuestion(' + i.toString() + '): No such question loaded')
}
}
};
</script>
</head>
<body onload = "Quiz.Init(document.querySelector('#Container'))">
<div id = 'Container'>
<!-- Container for the quiz -->
</div>
</body>
</html>
JSON.js 的作用
{
"questions": [
{"sex": ["male", "female"], "label": "What are you?"},
{"food": ["tacos", "spicynuts"], "label": "What do you eat?"},
{"team": ["team a", "team b", "team rocket"], "label": "Where do you belong to?"}
],
"answers": [
{"requirement": ["male", "tacos", "team a"], "message": "one has chosen male, tacos and team a"},
{"requirement": ["female", "tacos", "team a"], "message": "one has chosen female, tacos and team a"}
]
}
编辑:
我在写建议时遇到了一个小问题。根据您的解释“有七个问题和五个结果”,是否有些结果共享或没有结果呢?
更改
为了解决结果共享问题,我想到了两种我认为最简单的输入和维护方式。
我们将结果列出两次
这种解决方案听起来可能很愚蠢和太简单了。然而它很容易维护和管理。显然的缺点是缺乏数据完整性。
{"requirement": ["male", "spicynuts", "team a"], "message": "one has chosen male, spicynuts and team a"},
{"requirement": ["female", "spicynuts", "team a"], "message": "one has chosen male, spicynuts and team a"}
我们将需求嵌套在列表中
另一种方法是将需求(数组或对象)嵌套,这样您就可以简单地列出更多具有相同消息的需求。这种做法的缺点是,即使您从未需要它,您也必须以这种方式构建它。
{
"requirement": [
["male", "tacos", "team rocket"],
["male", "spicynuts", "team rocket"],
["female", "tacos", "team rocket"],
["female", "spicynuts", "team rocket"]
],
"message": "team rocket rocks my socks!"
}
结论
最终我决定让用户决定,并支持两种方法和初始解决方案的组合。可以像之前一样构建它,可以重复具有相同信息的答案,也可以嵌套要求。
我们需要改变什么?
主代码文件中的一个函数。
showResult: function(){
var tValues = [];
for(var i=0, j=this.mJSON.questions.length; i<j; i++)
if (this.mJSON.questions[i].value) tValues.push(this.mJSON.questions[i].value)
var tResult = 'No match for ' + tValues.join(',');
var tBreak = false;
for(var i=0, j=this.mJSON.answers.length; i<j && !tBreak; i++){
var tR = this.mJSON.answers[i].requirement;
var tRR = (typeof tR[0] === 'string') ? [tR] : tR;
for(var k=0, l=tRR.length; k<l && !tBreak; k++){
var tF = tValues.filter(function(e){return tRR[k].indexOf(e) === -1})
if (!tF || tF.length === 0){
tResult = this.mJSON.answers[i].message;
tBreak = true;
}
}
if (!tF || tF.length === 0){
tResult = this.mJSON.answers[i].message;
break;
}
}
var tH = document.createElement('h1');
tH.innerHTML = tResult;
this.mContainer.appendChild(tH)
},
这是用于测试的示例JSON:
{
"questions": [
{"sex": ["male", "female"], "label": "What are you?"},
{"food": ["tacos", "spicynuts"], "label": "What do you eat?"},
{"team": ["team a", "team b", "team rocket"], "label": "Where do you belong to?"}
],
"answers": [
{"requirement": ["male", "tacos", "team a"], "message": "one has chosen male, tacos and team a"},
{"requirement": ["female", "tacos", "team a"], "message": "one has chosen female, tacos and team a"},
{"requirement": ["male", "spicynuts", "team a"], "message": "one has chosen male, spicynuts and team a"},
{"requirement": ["female", "spicynuts", "team a"], "message": "one has chosen male, spicynuts and team a"},
{
"requirement": [
["male", "tacos", "team rocket"],
["male", "spicynuts", "team rocket"],
["female", "tacos", "team rocket"],
["female", "spicynuts", "team rocket"]
],
"message": "team rocket rocks my socks!"
}
]
}