效果图
代码
<template><!-- 考试题目页面 --><div><!-- 最外层div,循环几组题目 --><divv-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-radioclass="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.代表循环到的这一项被选中,就不动,如果不等于,代表没有选择,给nullif (aaa.length !== index + 1) {
aaa.push(null);}});//过滤一遍后给到form.radioArraythis.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,循环几组题目 --><divv-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-radiov-if="item.questionType=='判断题'?false:true":name="item.optionc"class="box">{
{
item.optionc }}</van-radio><van-radiov-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.listconsole.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代表是哪一题