最近公司做了一个测评系统,因为时间很短,本以为会很简单,没有想到踩了很多坑。
先看下部分效果图吧

然后在说下需求
1:所有的答案都是动态的(例如选择是出来的是第二题,选择否出来的是第五题)
2:没有答过的题不显示下一题按钮,答过的题显示上一题按钮
3:答过的题,返回上一题 显示上一题和下一题按钮(第一题和最后一题例外)
4:最后一题显示上一题和答案解析按钮
5:选择的时候 自动跳转到下一题
6:已经答过的题,更改后,从此题开始 后面答过的题清除(需求则是返回上一题,点击后不管有无更改 后面的题都清除,自己感觉不合理)
看似很简单,其实并不是很好处理 但是当思路捋清楚了 就很好做了
先捋一捋思路 无非三种操作 上一题、下一题、和答题和三种按钮状态 上一题 下一题 查看答案
然后开始拆分功能
首先是答题
1.判断是不是最后一题
1.1是:
1.1.1 显示上一题按钮
1.1.2显示答案解析按钮
1.2不是:
1.2.1显示下一题按钮
1.2.2 显示上一题按钮
1.2.3对比和之前的变化 当前题是否有值
1.2.3.1是 ==》哪一题开始清空
1.2.3.2否 ===》清空
2.选择赋值的时机
3. 当前题点击的时候 判断是不是最后一题 (已经答过的题)
3.1 当前题是第几题 =》从全部答案里面找 得到索引
3.2 判断当前提是否答过
答过:当前题的答案去匹配已经打过的题的当前题
判断下一题是否有
有==》不处理
五 ==》显示查看答案按钮
2.下一题
2.1 显示上一题
2.2过滤已经答过的题目 =》找到当前题的索引
2.3判断当前题的下一题是否存在
2.3.1不存在
判断是否显示查看答案的按钮
是 =》显示答案解析按钮
否 =》 显示下一题
2.3.2存在
显示下一题
判断是否最后一题 判断依据如下
1从全部题里面找到当前题
2从已经答过的题里面找到对应的索引‘
3当前题的题目答案中匹配已答项的答案
4判断当前题答案中是否有下一题
有==》不处理
无==》显示答案解析按钮
3 上一题
3.1 显示下一题按钮
3.2 判断上一题按钮是否显示
3.3 显示上一题
3.4 记录答案
看一下完整代码吧(vue3+vant)
- <template>
- <div class="main">
- <template v-for="(item, i) in vDate.dataList" :key="i">
- <div class="item_list" v-show="item.questionId == vDate.questionId">
- <div class="item_title">
- {{ item.question }}
- </div>
- <van-radio-group
- v-model="vDate.answerList[i].questionOptionId"
- >
- <van-radio
- @click="radioClick(i,item,key)"
- v-for="(key, v) in item.optionList"
- :key="v"
- :name="key.questionOptionId"
- >{{ key.questionOption }}</van-radio
- >
- </van-radio-group>
- </div>
- </template>
- <div class="operate">
- <div>
- <van-button size="small" v-if="vDate.press>0" @click="press">上一题</van-button>
- <span v-else></span>
- </div>
- <div>
- <div v-if="vDate.next>0">
- <van-button type="primary" size="small" @click="lookAnswer" v-if="vDate.isAnswer">查看答案</van-button>
- <van-button type="primary" size="small" @click="next" v-else>下一题</van-button>
- </div>
- <div v-else>
- </div>
- </div>
- </div>
- </div>
- <div>
- <van-overlay :show="vDate.show">
- <div class="wrapper" @click.stop>
- <van-cell-group inset>
- <div class="label">手机号</div>
- <van-field
- v-model="vDate.phone"
- center
- type="digit"
- :maxlength="11"
- placeholder="请输入手机号"
- >
- <template #button>
- <van-button type="primary" @click="vDate.flag && obtain()">{{vDate.content}}</van-button>
- </template>
- </van-field>
- <div class="input_control">
- <van-field v-model="vDate.pwdVal" :maxlength="4" type="digit" ref="verification" />
- </div>
- <div class="label">验证码</div>
- <div class='input_row' @click='getFocus'>
- <div class='pwd_item' v-for="(item,i) in 4" :key='i'>
- <span v-if="vDate.pwdVal.length>i">{{vDate.pwdVal[i]}}</span>
- </div>
- </div>
- <div class="operation">
- <van-button type="primary" block @click="toDetail">查看答案</van-button>
- </div>
- </van-cell-group>
- </div>
- </van-overlay>
- </div>
- </template>
- <script setup lang="ts">
- import { nextTick, reactive, ref,onMounted } from "vue";
- const verification = ref()
- import {useRouter} from "vue-router"
- import { Toast } from 'vant';
- import {getQuestionList,submitQuestionList} from "@/api/index"
- const router = useRouter()
- const vDate:any = reactive({
- type:0,
- phone:'',
- show:false,
- flag:true,
- input:false,
- pwdVal:"",
- count:'',
- content:'获取验证码',
- countNumber:1,
- timer:null,
- dataList: [
- ],
- answerList:[
- ],
- questionId:'',
- isAnswer:false,
- idList:[],
- press:0,
- isNext:'',
- next:0,
- index:0,
- answerLists:[]
- })
- const phoneReg= /^1[3-9][0-9]{9}$/
- // 上一题
- function press(){
- vDate.next = 1
- vDate.isAnswer = false
- let answerList = vDate.answerList.filter((item:any)=>item.questionId)
- let length = answerList.length-1
- let index = answerList.findIndex((item:any)=>item.questionId==vDate.questionId)
- if(index==-1){
- vDate.press = answerList.length-1
- vDate.questionId = answerList[length].questionId
- }else{
- vDate.press = index-1
- vDate.questionId = answerList[index-1].questionId
- }
- vDate.answerLists = JSON.parse(JSON.stringify(vDate.answerList))
- }
- function next(){
- vDate.press = 1
- let answerList = vDate.answerList.filter((item:any)=>item.questionId)
- let index = answerList.findIndex((item:any)=>item.questionId == vDate.questionId )
- if(answerList[index+1]){
- vDate.questionId = answerList[index+1].questionId
- let nextArr = vDate.dataList.filter((item:any)=>item.questionId == vDate.questionId) //当前页项
- let indexs = vDate.answerList.findIndex((item:any)=>item.questionId == vDate.questionId)
- console.log(vDate.questionId,vDate.answerList[indexs],999,nextArr[0],"===========")
-
- let arr = nextArr[0].optionList.filter((item:any)=>item.questionOptionId == vDate.answerList[indexs].questionOptionId)
- if(!arr[0].relationQuestionId){
- vDate.isAnswer = true
- vDate.next = 1
- }
- }else{
- if(!vDate.isNext){
- vDate.isAnswer = true
- }else{
- vDate.next = -1
- vDate.questionId = vDate.isNext
- console.log(vDate.questionId,"22")
- }
- }
- }
- // 查看答案
- const lookAnswer = ()=>{
- vDate.show = true
- }
- // 输入验证码
- const getFocus = ()=>{
- nextTick(()=>{
- verification.value.focus()
- })
- }
- //答案
- const toDetail = ()=>{
- if(!vDate.phone){
- return Toast('请输入手机号');
- }
- if(!phoneReg.test(vDate.phone)){
- return Toast('请输入正确手机号');
- }
- if(vDate.countNumber==1&&!vDate.pwdVal){
- return Toast('请获取验证码');
- }
- if(vDate.countNumber==2&&!vDate.pwdVal){
- return Toast('请输入验证码');
- }
- let userAnswerRequestList = vDate.answerList.filter((item:any)=>item.questionId)
- let params = {
- questionGroup:1,
- userAnswerRequestList
- }
- submitQuestionList(params).then((res:any)=>{
- localStorage.setItem("answerBatchNo",res.data)
- router.push("/answerDetail")
- })
-
- }
- //获取验证码
- const obtain = ()=>{
- if(!vDate.phone){
- return Toast('请输入手机号');
- }
- if(!phoneReg.test(vDate.phone)){
- return Toast('请输入正确手机号');
- }
- setTimeoutInfo()
- }
- //定时器
- const setTimeoutInfo = ()=>{
- const TIME_COUNT = 60;
- vDate.countNumber = 2
- vDate.flag = false
- if (!vDate.timer) {
- vDate.count = TIME_COUNT;
- vDate.timer = setInterval(() => {
- if (vDate.count > 0 && vDate.count <= TIME_COUNT) {
- vDate.count--;
- vDate.content = vDate.count+' s后获取';
- } else {
- vDate.content = '获取验证码';
- vDate.flag = true;
- clearInterval(vDate.timer);
- vDate.timer = null;
- }
- }, 1000)
- }
- }
- const radioClick = (i:number,item:any,val:any)=>{
- if(val.relationQuestionId!=null){
- setTimeout(()=>{
- vDate.questionId = val.relationQuestionId
- vDate.press = i+1
- vDate.next = -1
- vDate.isNext = val.relationQuestionId
- let index = vDate.answerList.findIndex((item:any)=>item.questionId == val.relationQuestionId)
- if(index==-1){
- vDate.answerList.forEach((item:any,v:number)=>{
- if(v>i){
- item.questionId = ""
- item.questionOptionId = ""
- }
- })
- }else{
- let arr = vDate.answerList.map((item:any,i:number)=>{
- return vDate.answerList[i].questionOptionId!=vDate.answerLists[i].questionOptionId
- })
- let indexs = arr.findIndex((item:any)=>item==true)
- if(indexs!=-1){
- vDate.answerList.forEach((item:any,v:number)=>{
- if(v>indexs){
- item.questionId = ""
- item.questionOptionId = ""
- }
- })
- }
- }
- clearTimeout()
- },300)
- }else{
- vDate.isAnswer = true
- vDate.next = 1
- vDate.isNext = null
- }
- vDate.answerList[i].questionId = item.questionId
- console.log(vDate.answerList,"vDate.answerList111")
- setTimeout(()=>{
- let index = vDate.dataList.findIndex(((item:any)=>item.questionId == val.relationQuestionId))
- if(index!=-1){
- let nextArr = vDate.dataList[index] //当前页项
- let flag = vDate.answerList[index].questionId
- if(flag){
- let arr = nextArr.optionList.filter((item:any)=>item.questionOptionId == vDate.answerList[index].questionOptionId)
- if(!arr[0].relationQuestionId){
- vDate.isAnswer = true
- vDate.next = 1
- }
- }
- }
- },500)
-
- }
- //获取题目
- const queryList = ()=>{
- let params = {
- questionGroup:1
- }
- getQuestionList(params).then((res:any)=>{
- vDate.dataList = res.data
- res.data.forEach((item:any)=>{
- vDate.idList.push(item.questionId)
- vDate.answerList.push({
- questionId:'',
- questionOptionId:''
- })
- })
- vDate.questionId = res.data[0].questionId
- vDate.answerLists = JSON.parse(JSON.stringify(vDate.answerList))
- })
- }
- onMounted(()=>{
- queryList()
- })
- </script>
看下题目的数据结构

感兴趣的小伙伴可以自己动手试一试 看似简单的东西 里面很有多坑 有需求的可以私信我 免费获取全部代码