vue实现单选做题根据对错标色,作对跳转下一题,实现思路详解

vue实现单选做题效果详解

最近在做一个答题项目,废了好多时间,经过折腾和在大佬的指导下,终于清晰的了解逻辑,如果你也遇到此类问题,不妨先看看我的思路,看完点个赞,那是继续跟新的动力

此案例是使用swiper以及vue来完成的。

需求分析,当点击了正确答案,选项背景色成指定的颜色,并且有一个打勾的效果,不能在选择其他选项,错误选项背景色改成对应的颜色,打上一个小叉,答对了自动切换到下一个题目,点击选项显示对应的答案及其解析。

主要涉及的知识点,vue 动态绑定class ,条件渲染,话不多说,首先先来看看效果

在这里插入图片描述
在这里插入图片描述

先详解在,在上源码,

先看布局,这里可以自己根据需求来布局

  <div  v-cloak id='app' class="recommendPage">
        <div class="swiper-container">
            <div class="swiper-wrapper">
                <div class="swiper-slide" v-for="(item, index) in tmList" :key="index">
                    <div class="box">
                        <van-divider class="qes-num"> {{ index + 1 }}/{{tmList.length}}</van-divider>
                        <p class="title">{{item.title}}</p>
                        <div class="anlist">
                            <ul>

								<li :class="{
						    	'success-active': item.userAnswer === subIndex,
								'error-active':item.userAnswer!==item.correct && item.userAnswer === subIndex}"
												v-for="(sub, subIndex) in item.answer" :key="sub.id" class="lis"
												@click="chechan(item,sub,  index,subIndex)">
									{{ sub }}
								 </li>
                            </ul>
                        </div>
                        <div v-if="isShowAnswer===index||item.userAnswer!==-1">
                            <div class="mar20">
                                正确答案: <span class="redcol"> {{ item.answer[item.correct] }}</span>
                            </div>
                            <div class="mar20 pa20">解析: {{ item.content }}</div>
                        </div>
                    </div>
                </div>
            </div>
        </div>

再看逻辑

<script>
    const app = new Vue({
        el: "#app",
        data() {
            return {
                swiper: {},
                isShowAnswer: -1,// 控制是否显示解析
                isActive: -1,
                tmList: [
                    {
                        id: 1,
                        title: '1、1947年12月,毛泽东在《目前形势和我们的任务》中总结出十大军事原则,其核心是( )',
                        correct: 0,
                        answer: [
                            'A.集中优势兵力,各个歼灭敌人',
                            'B.诱敌深入,积极防御',
                            'C.多种作战形式,适时转变',
                            'D.避其主力,打其虚弱'
                        ],
                        userAnswer: -1,  
                        content: "毛泽东于1947年12月25日在中共中央召开的会议上所做《目前形势和我们的任务》的报告中正式提出十大军事原则。十大军事原则是一个有机的整体,其核心是强调集中优势兵力打歼灭战", 
                    },
                    {
                        id: 2,
                        title: '2、中国宋代哲学家朱熹提出“理在事先”,把“天理”说成是世界万物的本原。这是一种( )',
                        correct: 1,
                        answer: ['A.主观唯心主义观点', 'B.客观唯心主义观点', 'C.朴素唯物主义观点', 'D.形而上学唯物主义观点'],
                        userAnswer: -1,  
                        content: "主观唯心主义认为物质是某种主观精神的产物,客观唯心主义将物质归结为某种客观精神的产物。结合题干可得,“理在事先”这种“天理”观属于客观唯心主义。",
                    },
                    {
                        id: 3,
                        title: '3、毛泽东在《新民主主义论》中提出的新民主主义文化纲领是( )',
                        correct: 2,
                        answer: [
                            'A.为抗战服务',
                            'B.为工农兵服务',
                            'C.民族的、科学的、大众的文化',
                            'D.古为今用,洋为中用'
                        ],
                        userAnswer: -1, 
                        content: "新民主主义的文化就是“无产阶级领导的,人民大众的,反帝反封建的文化”。这种文化是无产阶级领导的民族的、科学的、大众的文化。",
                    },
					{
					    id: 4,
					    title: '4、下列选项中,强调外因在事物发展中起着重要作用的是( )',
					    correct: 2,
					    answer: [
					        'A.出淤泥而不染',
					        'B.威武不能屈,贫贱不能移',
							'C.近朱者赤,近墨者黑',
							'D.常在河边走,就是不湿鞋'
					    ],
					    userAnswer: -1, 
					    content: "在因果联系中,内因是事物变化的根据,外因是事物变化的条件。“近朱者赤,近墨者黑”强调的是外因在事物变化发展中的重要作用。",
					}
                ],
            }
        },
        methods: {
            chechan(v1, v2, index, index1) {
		      
                if (v1.userAnswer !== -1) return // 代表已经答过了
                this.isActive = index1//选中当前选项
                this.isShowAnswer = index //选完显示答案和解析
                 v1.userAnswer = index1;   //此处非常关键,已经改变了 tmList数组
                if (index1 === v1.correct) {
                    this.nextto();
                } 
                console.log("点击的答案" + v1, "正确答案" + `${v2}`, "第" + `${index + 1}` + "题", `点击了第${index + 1}题的第${index1 + 1}答案`);
           
				//判断最后一个  此判断只适用于最后一个题目的答案 和没一道题的 选项唯一   根据自己的业务判断最后一个题
				let clicklast = v1.content;
                let arrlast = this.tmList[this.tmList.length-1].content;
				if(clicklast==arrlast){
				       alert("恭喜你完成答题")
				}
				
            },

            nextto() {
                //获取当前索引
                let thisindex = this.swiper.activeIndex;
                this.swiper.slideTo(thisindex + 1, 1000, false);
            },
        },
        mounted() {
            let that = this;
            that.swiper = new Swiper('.swiper-container', {
                initialSlide: 0, //默认显示
		        autoplay:false,//等同于以下设置
                on: {
                    touchStart: function () {
                        // alert(this.activeIndex);//切换结束时,告诉我现在是第几个slide
                    },
                },
            })
        },
        created() {
             
        }
    });
</script>
  • 1.先来看最简单的 显示对应题目的解析和答案
isShowAnswer===index||item.userAnswer!==-1

首先isShowAnswer 默认值为-1.index就是当前题目的下标,只有当isShowAnswer和下标相等的时候,就显示,所以在点击事件中只需要将isShowAnswer 与当前题目的下标相等即可。this.isShowAnswer = index,显然这样是可以显示对应的题目的解析答案,当我们切下一个题目的时候,在滑动回来上一题,刚才显示的答案又被影藏了,显然是下标不等了,观察数据结构,每一个题目中都有一个userAnswer: -1,的字段,那么我们点击选项的时候,我们就将这个值变成点击的答案的下标,v1.userAnswer = index1;往上自己了解这一句,这一句非常关键,这里的参数v1也就是题目的每一条数据,神奇的是,你可以通过打印,如果你这样赋值之后,加入我们点击的是第一道题目的第一个选项,题目数组中的第一条数据将变成

 {
 id: 1,
     title: '1、1947年12月,毛泽东在《目前形势和我们的任务》中总结出十大军事原则,其核心是( )',
     correct: 0,
     answer: [
         'A.集中优势兵力,各个歼灭敌人',
         'B.诱敌深入,积极防御',
         'C.多种作战形式,适时转变',
         'D.避其主力,打其虚弱'
     ],
     userAnswer: 0,  
     content: "毛泽东于1947年12月25日在中共中央召开的会议上所做《目前形势和我们的任务》的报告中正式提出十大军事原则。十大军事原则是一个有机的整体,其核心是强调集中优势兵力打歼灭战", 
userAnswer: 0, 

所以我们在加上一个条件 ||item.userAnswer!==-1,这样当我们做过题目之后,每条数据的userAnswer字段经等于点击答案的下标,不在是-1,从而只要我们答题过后,切换回来,刚才显示的答案依然还是显示出来。

  • 2.再看正确答案标色
    我们给每一个答案都动态绑定一个一个样式
:class="{
'success-active': item.userAnswer === subIndex,
'error-active':item.userAnswer!==item.correct && item.userAnswer === subIndex}"
v-for="(sub, subIndex) in item.answer" :

从字面上不难看出,一个是正确的样式,一个是错误的样式。

item.userAnswer === subIndex

从点击事件中不难看出 v1.userAnswer = index1;点击了哪个答案就让他 添加上success-active的样式,那有的小伙伴想。万一我点击的是错误的答案呢,不要着急,仔细看error-active 它还需要&& 一个条件才成立item.userAnswer!==item.correct
从数据结构中不难看出

 {
 id: 1,
 title: '1、1947年12月,毛泽东在《目前形势和我们的任务》中总结出十大军事原则,其核心是( )',
 correct: 0,
 answer: [
     'A.集中优势兵力,各个歼灭敌人',
     'B.诱敌深入,积极防御',
     'C.多种作战形式,适时转变',
     'D.避其主力,打其虚弱'
 ],
 userAnswer: -1,  
 content: "毛泽东于1947年12月25日在中共中央召开的会议上所做《目前形势和我们的任务》的报告中正式提出十大军事原则。十大军事原则是一个有机的整体,其核心是强调集中优势兵力打歼灭战", 
},
correct字段标识正确答案的选项,0就是`answe`r中的第一项,那表示第一个就是正确答案

所以取值正确答案即为 正确答案: <span class="redcol"> {{ item.answer[item.correct] }}</span>

比如第一题 ,当我们本来正确答案是A,假如我蛮点击了B,那此时 userAnswer是不是等于了1 ,1不等于correct是不是代表我们选择错误的答案。所以只要保证item.userAnswer!==item.correct && item.userAnswer === subIndex 说明我们点击的就是错误的。

最后再看,

  if (v1.userAnswer !== -1) return 

本来每一个数组中的每一条数据userAnswer都是1-只要点击过后,userAnswer就等于点击的答案下标,所以下一次点击的时候,表示这个题目已点击过了,直接return不在往下执行。

最后说一下打勾打叉。其实就是条件添加上对用的class之后,我们给当前类添加一个伪类样式即可。

  .anlist .success-active::before{
            position: absolute;
            content: "✔";
            top: 8px;
            left: 2px;
            font-size: 25px;
            color: #80e4ba;
        }
   .anlist .error-active::before{
            position: absolute;
            content: "×";
            top: 8px;
            left: 2px;
            font-size: 35px;
            color: #80e4ba;
        }

是不是没有想象中的那么复杂。

不是到这里就完了,一些小伙伴会问。我们后端返回的数据结构不是这样的呀,里面就没有userAnswer=-1的字段呀,那这个就很简单了,拿到数据遍历。像每一条数据中增加这样的一个字段,那不就完事了。然后还有一种可能,correct正确答案给的不是下标那怎么办,举个例子

   {
   id: 3,
          title: '3、毛泽东在《新民主主义论》中提出的新民主主义文化纲领是( )',
          correct: 2,
          answer: [
              'A.为抗战服务',
              'B.为工农兵服务',
              'C.民族的、科学的、大众的文化',
              'D.古为今用,洋为中用'
          ],
          userAnswer: -1, 
          content: "新民主主义的文化就是“无产阶级领导的,人民大众的,反帝反封建的文化”。这种文化是无产阶级领导的民族的、科学的、大众的文化。",
                    },

此题目不难看出正确答案就是C
如果后端给的数据书correct:'C.民族的、科学的、大众的文化' 那也简单,拿correctanswer数组中匹配,找到对应的下标即可。

总一,万变不离其中,你难道后台数据,将你的数据格式处理成上面的格式完事,无非就是遍历,追加字段。匹配一系列问题,差不多都是数组对象的简单玩法

                        重要事情说三遍,写了我一个小时,做个好人
                         **点赞**   **点赞**   **点赞**
                             *唯一跟新的动力*

完整代码

<!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">
    <script src="https://cdn.jsdelivr.net/npm/vue@2.6.14"></script>
    <link rel="stylesheet" href="https://unpkg.com/swiper@6.8.4/swiper-bundle.min.css">
    <script src="https://unpkg.com/swiper@6.8.4/swiper-bundle.min.js"> </script>
	<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/vant@2.12/lib/index.css"/>
	<script src="https://cdn.jsdelivr.net/npm/vant@2.12/lib/vant.min.js"></script>
    <title>单选做题</title>
    <style>
        * {
            padding: 0;
            margin: 0;
        }
          [v-cloak]{
            display: none
        }
		#app{
			width: 100%;
			height: 100%;
		 overflow: scroll;
		}
        ul li {
            list-style: none;
        }

   
        /* swiper */
        .swiper-container {
            width: 100vw;
            height: 100vh;
            background: #fff;
		
        }
        .swiper-container .swiper-slide {
            width: 100%;
            height: 100%;
            background: #fff;
            color: #000;
            font-size: 16px;
        }

        /* swiper */
        .box {
            width: 94%;
            margin: 0 auto;
        }

        .qes-num {
            margin-left: 8px;
        }

        .anlist {
            margin-top: 15px;
        }

        .anlist ul li {
            padding: 10px 0px;
            background: #f6f6f6;
            margin: 5px;
            border-radius: 7px;
            text-indent: 12px;
            overflow: hidden;
			text-overflow: ellipsis;
			white-space: nowrap;
        }

        .anlist .success-active {
            background: #021a02ad;
            color: #fff;
            position: relative;
        }

        .anlist .success-active::before{
            position: absolute;
            content: "✔";
            top: 8px;
            left: 2px;
            font-size: 25px;
            color: #80e4ba;
        }

        .anlist .error-active {
            background: #c15a5a;
            color: #fff;
            position: relative;
        }
        .anlist .error-active::before{
            position: absolute;
            content: "×";
            top: 8px;
            left: 2px;
            font-size: 35px;
            color: #80e4ba;
        }
        .van-radio {
            margin: 10px 0px;
        }

        .redcol {
            color: red;
        }

        .mar20 {
            margin: 20px auto;
        }
		.pa20{
		background: #7c937014;
		    padding: 10px;
		    border-radius: 10px;
		    font-size: 14px;
		    color: #999;
		    line-height: 28px;
		}
    </style>
</head>

<body>
    <div  v-cloak id='app' class="recommendPage">
        <div class="swiper-container">
            <div class="swiper-wrapper">
                <div class="swiper-slide" v-for="(item, index) in tmList" :key="index">
                    <div class="box">
                        <van-divider class="qes-num"> {{ index + 1 }}/{{tmList.length}}</van-divider>
                        <p class="title">{{item.title}}</p>
                        <div class="anlist">
                            <ul>

								<li :class="{
						    	'success-active': item.userAnswer === subIndex,
								'error-active':item.userAnswer!==item.correct && item.userAnswer === subIndex}"
												v-for="(sub, subIndex) in item.answer" :key="sub.id" class="lis"
												@click="chechan(item,sub,  index,subIndex)">
									{{ sub }}
								 </li>
                            </ul>
                        </div>
                        <div v-if="isShowAnswer===index||item.userAnswer!==-1">
                            <div class="mar20">
                                正确答案: <span class="redcol"> {{ item.answer[item.correct] }}</span>
                            </div>
                            <div class="mar20 pa20">解析: {{ item.content }}</div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
</body>
<script>
    const app = new Vue({
        el: "#app",
        data() {
            return {
                swiper: {},
                isShowAnswer: -1,// 控制是否显示解析
                isActive: -1,
                tmList: [
                    {
                        id: 1,
                        title: '1、1947年12月,毛泽东在《目前形势和我们的任务》中总结出十大军事原则,其核心是( )',
                        correct: 0,
                        answer: [
                            'A.集中优势兵力,各个歼灭敌人',
                            'B.诱敌深入,积极防御',
                            'C.多种作战形式,适时转变',
                            'D.避其主力,打其虚弱'
                        ],
                        userAnswer: -1,  
                        content: "毛泽东于1947年12月25日在中共中央召开的会议上所做《目前形势和我们的任务》的报告中正式提出十大军事原则。十大军事原则是一个有机的整体,其核心是强调集中优势兵力打歼灭战", 
                    },
                    {
                        id: 2,
                        title: '2、中国宋代哲学家朱熹提出“理在事先”,把“天理”说成是世界万物的本原。这是一种( )',
                        correct: 1,
                        answer: ['A.主观唯心主义观点', 'B.客观唯心主义观点', 'C.朴素唯物主义观点', 'D.形而上学唯物主义观点'],
                        userAnswer: -1,  
                        content: "主观唯心主义认为物质是某种主观精神的产物,客观唯心主义将物质归结为某种客观精神的产物。结合题干可得,“理在事先”这种“天理”观属于客观唯心主义。",
                    },
                    {
                        id: 3,
                        title: '3、毛泽东在《新民主主义论》中提出的新民主主义文化纲领是( )',
                        correct: 2,
                        answer: [
                            'A.为抗战服务',
                            'B.为工农兵服务',
                            'C.民族的、科学的、大众的文化',
                            'D.古为今用,洋为中用'
                        ],
                        userAnswer: -1, 
                        content: "新民主主义的文化就是“无产阶级领导的,人民大众的,反帝反封建的文化”。这种文化是无产阶级领导的民族的、科学的、大众的文化。",
                    },
					{
					    id: 4,
					    title: '4、下列选项中,强调外因在事物发展中起着重要作用的是( )',
					    correct: 2,
					    answer: [
					        'A.出淤泥而不染',
					        'B.威武不能屈,贫贱不能移',
							'C.近朱者赤,近墨者黑',
							'D.常在河边走,就是不湿鞋'
					    ],
					    userAnswer: -1, 
					    content: "在因果联系中,内因是事物变化的根据,外因是事物变化的条件。“近朱者赤,近墨者黑”强调的是外因在事物变化发展中的重要作用。",
					}
                ],
            }
        },
        methods: {
            chechan(v1, v2, index, index1) {
		      
                if (v1.userAnswer !== -1) return // 代表已经答过了
                this.isActive = index1//选中当前选项
                this.isShowAnswer = index //选完显示答案和解析
                 v1.userAnswer = index1;   //此处非常关键,已经改变了 tmList数组
                if (index1 === v1.correct) {
                    this.nextto();
                } 
                console.log("点击的答案" + v1, "正确答案" + `${v2}`, "第" + `${index + 1}` + "题", `点击了第${index + 1}题的第${index1 + 1}答案`);
           
				//判断最后一个  此判断只适用于最后一个题目的答案 和没一道题的 选项唯一   根据自己的业务判断最后一个题
				let clicklast = v1.content;
                let arrlast = this.tmList[this.tmList.length-1].content;
				if(clicklast==arrlast){
				       alert("恭喜你完成答题")
				}
				
            },

            nextto() {
                //获取当前索引
                let thisindex = this.swiper.activeIndex;
                this.swiper.slideTo(thisindex + 1, 1000, false);
            },
        },
        mounted() {
            let that = this;
            that.swiper = new Swiper('.swiper-container', {
                initialSlide: 0, //默认显示
		        autoplay:false,//等同于以下设置
                on: {
                    touchStart: function () {
                        // alert(this.activeIndex);//切换结束时,告诉我现在是第几个slide
                    },
                },
            })
        },
        created() {
             
        }
    });
</script>

</html>
  • 11
    点赞
  • 41
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Vue实现单选下一题功能,可以通过以下步骤实现: 1. 在Vue组件定义一个题目列表,以及当前题目的索引值。 2. 在模板渲染当前题目的题目内容和选项列表,并绑定选项的选择事件。 3. 在选项选择事件,更新当前题目的索引值,以便渲染下一题的内容。 4. 在渲染下一题之前,可以进行一些逻辑判断,例如判断当前题目是否已经是最后一题,或者判断用户是否已经选择了当前题目的选项等。 下面是一个简单的示例代码,用于演示如何在Vue实现单选下一题功能: ``` <template> <div> <h2>{{ questions[currentIndex].title }}</h2> <ul> <li v-for="(option, index) in questions[currentIndex].options" :key="index"> <label> <input type="radio" :value="option" v-model="selectedOption">{{ option }} </label> </li> </ul> <button @click="nextQuestion">下一题</button> </div> </template> <script> export default { data() { return { questions: [ { title: '问题1', options: ['选项1', '选项2', '选项3'], answer: '选项1' }, { title: '问题2', options: ['选项1', '选项2', '选项3'], answer: '选项2' }, { title: '问题3', options: ['选项1', '选项2', '选项3'], answer: '选项3' } ], currentIndex: 0, selectedOption: '' } }, methods: { nextQuestion() { if (this.selectedOption === '') { alert('请选择一个选项') return } if (this.currentIndex === this.questions.length - 1) { alert('已经是最后一题了') return } this.currentIndex++ this.selectedOption = '' } } } </script> ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

1登峰造极

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值