效果图
代码
<template>
<!-- 考试题目页面 -->
<div>
<!-- 最外层div,循环几组题目 -->
<div
v-for="(item, index) of list2"
:key="index"
style="margin-bottom: 10px"
>
<!-- 这是题目 -->
<p class="title">{{ item.title }}</p>
<!-- 这是选项 -->
<van-radio-group v-model="form.radioArray[index]">
<van-radio
class="box"
v-for="it of item.list"
:key="it.id"
:label="it.id"
:name="it.anames"
@click="handleRadioChanges(item, it.id)"
>{{ it.anames }}</van-radio
>
</van-radio-group>
</div>
</div>
</template>
<script>
/*
第一步:循环数组,里面有几组题目就循环多少个div
第二步:里面的van-radio-group部分也就是一组单选框,循环每组题目内的选项部分。配合上面的题目就实现了一组题目加选项的试题出来了。
第三步:选项点击后存入的变量form.radioArray[index],这里index是最外层容器循环的角标。比如第一次循环,出来了第一组题目和选项,这个时候index=0.那么这时候你点击存入的选项数据就存在form.radioArray[0],
然后第二次循环,出现第二组试题和选项,点击后选项数据存在form.radioArray[1],以此类推,就能把每一组的选项值存入到数组对应的位置,不会乱。这样数组内的第一个数据就是你第一组的题目选项。
第四步:点击选项的时候会触发方法,参数把你当前的这一组试题传过去,还有你选中项的id,然后handleRadioChanges方法接收后处理步骤:1,遍历每一个选项看哪一个和你传进来的id是一致的就代表这一项是你选中的单选框,
就把他的 pcStatus = 1,反之则=0,这个pcStatus代表是否选中,1代表选中,0代表未选中。然后把你的这一组数据去重,这一步是为了防止你点击第一组的选项1后存进去,然后点击选项2又存进去,就重复了,我们要的是单选,
所以用这个去重,如何去重呢,就是对比数组中的每组题目的id,就是那个000,001的。比如我发现我的数组内有两个id:000的那就去重,去掉前面的,我取最后一个,因为你点击的最后一项肯定是最终选中的项。最后经过筛选得出的
这个数组reslist,就是我们所有题目点击选项后的数据。里面是一个数组套几个对象,其实就是几个题目,根据每个题目中的pcStatus是否为1来判断这个题目选中的是哪一个选项。
注意事项:这里的van-radio标签上有个name属性,这个是标识符的意思,vant组件自带的属性。这个标识符需要用不同的,否则如果相同,你点击一个选项会把所有选项都选中,因为你没有区分标识符,程序认不出来你点击的是哪一个。
就会把所有相同标识符的都选中,这个地方只要不写死就行,我直接用的选项的名字当表示符,那基本就不会一样了。
最后:数据结构方面就需要跟后端配合,让后端给你传一个这样的数据结构,这样你就可以做出来,然后你选中后还是传一个这样的数据结构过去后端,后端根据每一组题目的哪一个选项pcStatus = 1来判断这一组选中的是什么,
从而给你返回这个人对应的考试分数
*/
export default {
data() {
return {
form: {
//单选部分渲染数据
radioArray: [],
},
//用来去重的数组
reslist: [],
act: '',
//后台传来的数据(模拟)
list2: [
{
title: "第一题",
id: "000",
list: [
{ id: "11", anames: "第一组1", pcStatus: null },
{ id: "12", anames: "第一组2", pcStatus: null },
{ id: "13", anames: "第一组3", pcStatus: null },
],
},
{
title: "第二题",
id: "001",
list: [
{ id: "21", anames: "第二组4", pcStatus: null },
{ id: "22", anames: "第二组5", pcStatus: null },
{ id: "23", anames: "第二组6", pcStatus: null },
],
},
{
title: "第三题",
id: "002",
list: [
{ id: "31", anames: "第三组1", pcStatus: null },
{ id: "32", anames: "第三组2", pcStatus: null },
{ id: "33", anames: "第三组3", pcStatus: null },
],
},
],
};
},
created() {
this.handCheck();
},
methods: {
// 赋值
handCheck() {
const aaa = [];
//循环每一项
this.list2.forEach((item, index) => {
item.list.forEach((it) => {
//看pcStatus是否等于1把id存进去
if (it.pcStatus === 1) {
aaa.push(it.id);
}
});
//循环时判断如果aaa的长度等于index加1.代表循环到的这一项被选中,就不动,如果不等于,代表没有选择,给null
if (aaa.length !== index + 1) {
aaa.push(null);
}
});
//过滤一遍后给到form.radioArray
this.form.radioArray = aaa;
},
// 取值
handleRadioChanges(item, id) {
console.log(item, id);
this.act = id;
//循环判断传过来的id和遍历的哪一个id一致就把他的pcStatus改为1,代表选中,否则给0带表未选中
item.list.forEach((res) => {
if (res.id === id) {
res.pcStatus = 1;
} else {
res.pcStatus = 0;
}
});
//把每一项给到新的数组去重,防止点的多个一样的存进数组。
this.reslist.push(item);
let newArry = this.reslist;
//数组去重选择最后一条数据
for (var i = 0; i < newArry.length; i++) {
for (var j = i + 1; j < newArry.length; j++) {
if (newArry[i].id == newArry[j].id) {
newArry.splice(i, 1);
j--;
}
}
}
this.reslist = newArry;
console.log(this.reslist);
},
},
};
</script>
<style scoped>
.box {
height: 50px;
text-align: center;
line-height: 50px;
border-radius: 20px;
margin-bottom: 2px;
padding-left: 40px;
font-size: 16px;
border-bottom: 1px #ccc solid;
}
.title {
height: 50px;
text-align: center;
line-height: 50px;
margin-bottom: 2px;
background-color: #007bbb;
font-size: 16px;
color: #fff;
font-weight: bold;
}
</style>
8.30号更新!!!
经过和后端的沟通,发现他们给我的数据格式不是我上面想要的这种,要求我返回给他的数据是一个题目的id和对应选中的答案,所以经过摸索,我又想出了一套写法。特地放出来让大家看看,有遇到一样情况的可以参考
先上效果图(后端给的数据格式)
代码
注意事项:
1,因为后端给我传的数据格式我不好循环答案,所以我要先写死四个,然后他还有判断题,这样我就把后两个答案用v-if根据他给的类型来判断,如果是判断题那就隐藏两个就行了。
2,:name属性一定要有,后面跟不同的值用来区分,否则你点一个单选框会全部都选中的。
思路:通过van-radio-group的v-model,我给了角标index区分,会把对应选中的数据保存到form.radioArray内角标对应位置,然后我们再通过change事件传递对应的id和角标,然后我们创建一个对象存放id和答案,然后去重过后就获得了一个答案的数组。数组内answer代表答案,id代表是哪一题,这样我们把数据转成字符串穿给后端就可以了,他们能根据对应的id和答案来给我们返回成绩
<template>
<!-- 考试题目页面 -->
<div>
<!-- 最外层div,循环几组题目 -->
<div
v-for="(item, index) of list3"
:key="index"
style="margin-bottom: 10px"
>
<!-- 这是题目 -->
<p class="title">{{ item.question }}</p>
<!-- 这是选项 -->
<van-radio-group v-model="form.radioArray[index]" @change="hand(item,item.id,index)">
<van-radio
:name="item.optiona"
class="box"
>{{ item.optiona }}</van-radio
>
<van-radio
:name="item.optionb"
class="box"
>{{ item.optionb }}</van-radio
><van-radio
v-if="item.questionType=='判断题'?false:true"
:name="item.optionc"
class="box"
>{{ item.optionc }}</van-radio
><van-radio
v-if="item.questionType=='判断题'?false:true"
:name="item.optiond"
class="box"
>{{ item.optiond }}</van-radio
>
</van-radio-group>
</div>
<div>
<van-button icon="edit" type="primary" @click="getinfo">完成考试</van-button>
</div>
</div>
</template>
<script>
export default {
data() {
return {
form: {
//单选部分渲染数据
radioArray: [],
},
//获取选中项对应题目和答案
value:[],
//单选项循环数据
list3:[]
};
},
created() {
this.getinfo2()
},
methods: {
//单选数据
hand(item,id,index){
let aa={id:id,answer:this.form.radioArray[index]}
this.value.push(aa)
for (var i = 0; i < this.value.length; i++) {
for (var j = i + 1; j < this.value.length; j++) {
if (this.value[i].id == this.value[j].id) {
this.value.splice(i, 1);
j--;
}
}
}
},
getinfo(){
//退回主页面
this.$router.go(-2)
},
getinfo2(){
this.$http({
url: this.$http.adornUrl("/app/shotexam/listOfType"),
method: "post",
params: this.$http.adornParams({
type:'jx'
}),
}).then(({ data }) => {
this.list3=data.list
console.log(data);
})
}
},
};
</script>
<style scoped>
.box {
height: 50px;
text-align: center;
line-height: 50px;
border-radius: 20px;
margin-bottom: 2px;
padding-left: 40px;
font-size: 16px;
border-bottom: 1px #ccc solid;
}
.title {
text-align: center;
line-height: 25px;
margin-bottom: 2px;
border: solid #ccc 1px;
background-color: #1989fa;
font-size: 16px;
color: #fff;
}
</style>
传给后端的数据格式图
这就是我们经过去重和筛选后,获取到的每一题的数据格式传给后端的。
answer代表答案,id代表是哪一题