Vue + vux 实现移动端在线考试小功能(单选、多选、判断)
<template><div class="examination-wrap bg-white"><div class="examination-content"><h4 class="examination-title">考试
·
<template>
<div class="examination-wrap bg-white">
<div class="examination-content">
<h4 class="examination-title">考试标题</h4>
<p class="examination-info">
<span>题量:9</span>
<span>总分:100</span>
<span>合格:60</span>
<span>答题时间:{{duration}}</span>
</p>
<ul class="examination-question-list">
<li :id="'anchor-'+num" v-for="(items,num) in testList" :key="num">
<h5>{{ num +1 }}.{{items.title}}
<span v-if="items.type === 0">[判断题]</span>
<span v-if="items.type === 1">[单选题]</span>
<span v-if="items.type === 2">[多选题]</span>
</h5>
<div v-if="items.type == 0">
<div class="answer-list">
<p>A. 正确</p>
<p>B. 错误</p>
</div>
<div class="check-content">
<span :class="{active: isSelected(items, 0)}" @click="selectOption(items,num,0)"><i class="iconfont icon-gouxuan"></i>A</span>
<span :class="{active: isSelected(items, 1)}" @click="selectOption(items,num,1)"><i class="iconfont icon-gouxuan"></i>B</span>
</div>
</div>
<div v-else>
<div class="answer-list">
<p v-for="(item, index) in items.options" :key="index">{{item}}</p>
</div>
<div class="check-content">
<span v-for="(item, index) in items.options" :key="index" :class="{active: isSelected(items, index)}" @click="selectOption(items,num,index)"><i class="iconfont icon-gouxuan"></i>{{numberToLetter(index)}}</span>
</div>
</div>
</li>
</ul>
</div>
<div class="cutdown-submit-wrap bg-white">
<div class="examination-num">
<a href="javascript:;" @click="selectIndex(index)" class="num-item" v-for="(item,index) in testList" :class="{selected: isDone(item), current: index === currentIndex}">{{index + 1}}</a>
</div>
<div class="cutdown-content">
<span class="cutdown-text">剩余时间:<span class="red">{{rest}}</span></span>
<x-button mini class="examination-submit-btn" @click.native="submitAnswer">提交试卷</x-button>
</div>
</div>
<!-- 提示弹窗 start-->
<div v-transfer-dom>
<confirm v-model="confirmShow" :cancel-text="readWrongText" :title="confirmTitle" @on-cancel="onCancel" @on-confirm="onConfirm">
<p style="text-align:center;">{{ confirmText }}</p>
</confirm>
</div>
<div v-transfer-dom>
<alert v-model="alertShow" :title="alertTitle" @on-hide="onHide"> {{ alertText }}</alert>
</div>
<!-- 提示弹窗 end-->
</div>
</template>
<script>
// 多选题数组选项处理
Array.prototype.contains = function (obj) {
var i = this.length
while (i--) {
if (this[i] === obj) {
return true
}
}
return false
}
import { XButton, Confirm, Alert, TransferDomDirective as TransferDom } from 'vux'
export default {
directives: {
TransferDom
},
components: {
XButton,
Confirm,
Alert
},
data () {
return {
alertShow: false,
alertTitle: '提示',
alertText: '',
alertType: 0,
confirmShow: false,
confirmTitle: '提示',
confirmText: '',
confirmType: 0,
readWrongText: '取消',
currentIndex: 0,
time: '1800',
endTime: null,
testList: [
{
type: 0,
title: 'title',
userAnswer: null
},
{
type: 1,
title: 'title',
options:[
'A. 选项',
'B. 选项',
'C. 选项',
'D. 选项'
],
userAnswer: null
},
{
type: 2,
title: 'title',
options:[
'A. 选项',
'B. 选项',
'C. 选项',
'D. 选项'
],
userAnswer: null
},
]
}
},
computed: {
duration () {
return this.fomart(this.time);
},
rest () {
return this.fomart(this.endTime);
}
},
mounted() {
this.$nextTick(function () {
this.updateTime();
})
},
methods: {
isSelected(item, index) {
if (item.type === 2) {
if (!item.userAnswer) {
return false
}
for (var answer of item.userAnswer) {
if (answer === index) {
return true
}
}
return false
} else {
return item.userAnswer === index
}
return false
},
isDone(item) {
if (item.type === 0) {
return item.userAnswer === 0 || item.userAnswer === 1
}
if (item.type === 1) {
return item.userAnswer || item.userAnswer === 0
}
if (item.type === 2) {
return item.userAnswer && item.userAnswer.length
}
return false
},
selectOption(item, num, index) {
this.currentIndex = num;
if (item.type === 2) {
var userAnswer = this.testList[this.currentIndex].userAnswer
if (!userAnswer) {
userAnswer = []
}
if (userAnswer.contains(index)) {
for (var i = 0; i < userAnswer.length; i++) {
if (userAnswer[i] === index) {
userAnswer.splice(i, 1)
return
}
}
}
userAnswer.push(index)
userAnswer = userAnswer.sort()
this.testList[this.currentIndex].userAnswer = userAnswer
} else {
this.testList[this.currentIndex].userAnswer = index
}
},
selectIndex(index) {
this.currentIndex = index
},
// 锚点选中和定位
selectIndex(index) {
this.currentIndex = index;
var anchor = this.$el.querySelector('#anchor-'+index);
document.querySelector('.content-scroll').scrollTop = anchor.offsetTop; // 这里的 document.querySelector('.content-scroll') 是一个div容器,如果想让window滚动定位,换成window就好了
},
submitAnswer() {
var that = this,answerArr = [],answerLen;
this.testList.forEach(function (item, index) {
if (item.userAnswer || item.userAnswer === 0) {
if (item.type === 1 || item.type === 0) {
answerArr.push(that.numberToLetter(item.userAnswer))
} else if (item.type === 2) {
var arr = [];
item.userAnswer.forEach(function (answer, index) {
arr.push(that.numberToLetter(answer))
})
answerArr.push(arr)
}
}
})
answerLen = this.testList.length - answerArr.length;
if (answerLen == 0) {
this.confirmShow = !this.confirmShow;
this.confirmText = '您确认提交吗!';
// console.log(this.fomart(this.time - this.endTime))
// console.log(answerArr)
} else {
this.alertShow = !this.alertShow;
this.alertText = '您还有' + answerLen + '题未做!';
}
},
updateTime() {
var that = this,time = this.time;
this.timer = setInterval(function () {
time = time - 1;
that.endTime = time;
if (time === 0){
clearInterval(that.timer);
that.alertShow = !this.alertShow;
that.alertType = 1;
that.alertText = '考试时间结束!';
}
}, 1000)
},
fomart(time) {
var h,m,s;
h = Math.floor(time / 3600);
m = Math.floor(time / 60 % 60);
s = Math.floor(time % 60);
h < 10 ? h = '0' + h : h = h;
m < 10 ? m = '0' + m : m = m;
s < 10 ? s = '0' + s : s = s;
return h + ':' + m + ':' + s;
},
numberToLetter(number) {
var arr = 'ABCD'
return arr[number]
},
onConfirm() {
var that = this;
if ( this.confirmType === 1 ){
this.$router.push({path: '/'})
} else {
clearInterval(this.timer);
setTimeout(function() {
that.viewScore();
},500)
}
},
viewScore() {
this.confirmShow = !this.confirmShow;
this.confirmType = 1;
this.confirmTitle = '成绩';
this.confirmText = '您的得分:70';
this.readWrongText = '查看错题';
},
onCancel() {
if ( this.confirmType === 1 ){
alert('进入错题中...')
}
},
onHide() {
if (this.alertType === 1){
this.$router.push({path: '/'})
}
}
}
}
</script>
<style lang="less">
.examination-content{
padding-bottom: 60px;
h4{
font-size: .8rem;
font-weight: 400;
text-align: center;
padding: 5px 0;
}
.examination-info{
font-size: .6rem;
border-top: 1px solid #eee;
border-bottom: 1px solid #eee;
padding: 5px 10px;
span{
margin-right: 4%;
}
}
.examination-question-list{
padding: 0 10px 20px;
font-size: .7rem;
h5{
font-size: .75rem;
font-weight: 400;
line-height: 20px;
margin-top: 15px;
}
.answer-list{
padding: 8px 0 0 6px;
line-height: normal;
p{
margin-bottom: 8px;
}
}
.check-content {
padding: 5px 0 8px;
border-bottom: 1px solid #eee;
span{
padding: 5px 10px;
&.active .iconfont:before{
content: '\e60f';
color: #09BB07;
}
}
.iconfont{
font-size: 1rem;
margin-right: 2px;
vertical-align: middle;
&:before{
color: #c9c9c9;
}
}
}
}
}
.cutdown-submit-wrap{
position: fixed;
bottom: 50px;
left: 0;
right: 0;
padding: 5px 10px;
border-top: 1px solid #eee;
.examination-num{
overflow: hidden;
.num-item{
float: left;
display: inline-block;
font-size: .6rem;
padding: 1px 8px;
margin-right: 4px;
margin-bottom: 6px;
border: 1px solid #ccc;
&.selected{
color: #fff;
border-color: #09BB07;
background-color: #09BB07;
}
}
}
.cutdown-content{
margin-top: 5px;
.cutdown-text{
font-size: .6rem;
.red{
font-size: .8rem;
}
}
.examination-submit-btn{
float: right;
color: #fff;
background-color: #f00;
&:after{
border: none;
}
}
}
}
</style>
更多推荐
已为社区贡献2条内容
所有评论(0)