更新记录
1.2.5(2024-03-29) 下载此版本
- 稍作优化
1.2.4(2024-02-21) 下载此版本
- 更新示例工程
- 更新文档
1.2.3(2024-02-06) 下载此版本
- 更新文档
- 兼容vue2的预更新进行中...
平台兼容性
Vue2 | Vue3 |
---|---|
× | √ |
App | 快应用 | 微信小程序 | 支付宝小程序 | 百度小程序 | 字节小程序 | QQ小程序 |
---|---|---|---|---|---|---|
HBuilderX 3.1.0 app-vue | × | √ | × | × | × | × |
钉钉小程序 | 快手小程序 | 飞书小程序 | 京东小程序 |
---|---|---|---|
× | × | × | × |
H5-Safari | Android Browser | 微信浏览器(Android) | QQ浏览器(Android) | Chrome | IE | Edge | Firefox | PC-Safari |
---|---|---|---|---|---|---|---|---|
√ | √ | √ | √ | √ | √ | √ | √ | √ |
sv-exam
前言
- 这是一款未使用任何第三方库的刷题考试系统插件,包含三种模式:背题模式、刷题模式、模拟考试
- 目前经实测,已兼容微信小程序、安卓App、H5三端,其他平台未实测
- 如需商用,还请加群私聊联系作者本人,加群方式见本文结尾
重要公告!!!
- 在2024/02/21日v1.2.4版本后,除了部分重大bug或问题外,此插件将不会再频繁更新,以后将会在sv-exam-plus插件中不断更新迭代
- 该sv-exam-plus是基于本sv-exam的基础上,对vue2/3进行了适配兼容,详情请点击sv-exam-plus
简介
- 背题模式:用户可以查看题目和答案,但不能进行答题操作
- 刷题模式:用户可以进行答题操作,并记录答题情况
- 模拟考试:用户可以进行答题操作,并记录答题情况,系统会根据答题情况给出模拟考试的成绩
- 题目、选项、解析部分均支持富文本内容,可以添加图片等较为丰富的内容
功能
除上述三种模式外,还开放以下功能事件:
- 题目收藏
- 答题记录(根据做题情况添加记录或错题本)
- 纠错反馈
- 退出确认事件(考试模式下会弹出退出提示框,确认返回后方可离开考试)
使用方式
建议一键导入示例工程,参照示例工程使用
<template>
<view class="exam">
<sv-exam
:type="examOptions.type"
:data="examData"
:lib="examOptions.lib"
:favs="myFavs"
@changePaper="changePaper"
@quit="onQuit">
</sv-exam>
</view>
</template>
<script setup>
import { ref } from 'vue';
import { onLoad, onUnload } from '@dcloudio/uni-app'
import data from '/assets/json/temp-data.js'
import { cloneDeep } from 'lodash'
const tempdata = cloneDeep(data) // 深拷贝原数据,防止数据污染
const examOptions = ref({})
const examData = ref([]) // 题目列表
const myFavs = ref([]) // 收藏夹
onLoad((options) => {
examOptions.value = options // type:三种考试类型exam/practice/recite, lib:题库id
handleData(options)
todoContinue()
// 开启相关事件监听
examWatcher()
})
// 数据处理
function handleData(options) {
setTimeout(() => {
// 模拟从接口异步获取题目数据
examData.value = findPaperFromData(options.lib)
myFavs.value = uni.getStorageSync('sv-exam-fav') || []
}, 1000)
}
// 继续进度刷题
function todoContinue() {
if (examOptions.value.type !== 'practice') return
let dataCache = uni.getStorageSync('sv-exam-data-cache')
if (dataCache[examOptions.value.lib]?.length > 0) {
uni.showModal({
title: '系统提示',
content: '是否继续上次答题?',
showCancel: true,
success: ({ confirm }) => {
if (confirm) {
examData.value = dataCache[examOptions.value.lib]
} else {
// 重新开始答题
uni.$emit('sv-exam-start', 0)
}
}
})
}
}
// 获取指定题库的题目列表
function findPaperFromData(lib) {
let temp = tempdata.filter(item => item.from_lib == lib)
if (examOptions.value.type == 'exam') {
// 打乱顺序取随机100道
temp = shuffleAndPickTen(temp, 100)
}
return temp
}
// 考试模式需随机打乱题库并取其中num道题目,num默认100
function shuffleAndPickTen(arr, num = 100) {
// 打乱数组
function shuffle(array) {
for (let i = array.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[array[i], array[j]] = [array[j], array[i]]
}
return array
}
// 打乱后的数组取前num个(或数组长度不足num时全部)
const shuffledArr = shuffle(arr)
return shuffledArr.slice(0, Math.min(shuffledArr.length, num))
}
/**
* 切换题目
* @param {Object} e 当前题目
*/
function changePaper(e) {
console.log('==== 切换题目 :', e)
}
/**
* 退出考试
* @param {Object} e 做题记录,可缓存或上传云端,用作下一次打开后继续进度
*/
function onQuit(e) {
if (examOptions.value.type == 'practice') {
const storage = uni.getStorageSync('sv-exam-data-cache') || {}
storage[examOptions.value.lib] = e
uni.setStorageSync('sv-exam-data-cache', storage)
}
console.log('==== 退出考试 :', e)
}
// exam相关事件监听
function examWatcher() {
/**
* 监听题目提交
* @param e 题目记录: 可根据返回的题目记录,自定义选择存入做题记录或错题本
*/
uni.$on('e-exam-paper-item-submit', (e) => {
console.log('==== 监听题目提交 e-exam-paper-item-submit :', e)
})
/**
* 监听考完交卷
* @param e 答题记录列表: 可根据返回的答题记录列表,缓存或上传云端,提示下一次打开是否继续上次答题
*/
uni.$on('e-exam-paper-complete', (e) => {
console.log('==== 监听考完交卷 e-exam-paper-complete :', e)
})
/**
* 监听题目收藏
* @param e 收藏题目数据
*/
uni.$on('e-exam-paper-item-fav', (e) => {
const favStorage = uni.getStorageSync('sv-exam-fav') || []
if (e.isfav) {
// 添加收藏
favStorage.push(e.paper.data)
} else {
// 移除收藏
favStorage.splice(favStorage.findIndex(item => item.exam_id === e.paper.data.exam_id), 1)
}
uni.setStorageSync('sv-exam-fav', favStorage)
// 将新的收藏列表更新至myFavs
myFavs.value = favStorage
console.log('==== 监听题目收藏 e-exam-paper-item-fav :', e)
})
/**
* 监听纠错反馈
* @param e 纠错反馈的题目
*/
uni.$on('e-exam-paper-item-feedback', (e) => {
console.log('==== 监听纠错反馈 e-exam-paper-item-feedback :', e)
})
}
onUnload(() => {
// 统一做exam所有事件监听移除操作
uni.$off('e-exam-paper-item-submit')
uni.$off('e-exam-paper-complete')
uni.$off('e-exam-paper-item-fav')
uni.$off('e-exam-paper-item-feedback')
})
</script>
<style>
.exam {
width: 100%;
height: calc(100vh - var(--window-top));
}
</style>
其他场景使用方式
例如在部分其他场景,比如:收藏本,错题本中,开启刷题时需要跳转至刷题页面,但是可能不需要答题卡等部分功能,为此提高代码复用性,在1.1.8版本提供简约形式使用,案例如下:
// simple-exam.vue页面
<template>
<view class="exam">
<view class="exam-container">
<sv-exam
type="practice" // --- 默认为刷题模式
:data="examData"
:showCard="false" // --- 关闭答题卡
@changePaper="changePaper"
@quit="onQuit">
</sv-exam>
</view>
</view>
</template>
<script setup>
import { computed, ref, getCurrentInstance, nextTick } from 'vue'
import { onLoad, onUnload } from '@dcloudio/uni-app'
import { useSysStore } from '@/store/sys'
const { proxy } = getCurrentInstance();
// 题目列表
const examData = ref([])
onLoad((options) => {
// 通信通道传值 - 只监听一次
const eventChannel = proxy.getOpenerEventChannel()
eventChannel.once('e-transmit-exams', (res) => {
examData.value = res.data // 从错题本或试题收藏夹页面传过来试题列表
nextTick(() => {
// 默认试题索引需要在页面渲染后赋予
uni.$emit('sv-exam-start', res.index) // 从错题本或试题收藏夹页面传过来试题索引
})
})
// 开启监听者
examWatcher()
})
function examWatcher() {
/**
* 监听题目提交
* @param e 题目记录: 可根据返回的题目记录,自定义选择存入做题记录或错题本
*/
uni.$on('e-exam-paper-item-submit', async (e) => {
console.log('==== 监听题目提交 e-exam-paper-item-submit :', e)
})
/**
* 监听纠错反馈
* @param e 纠错反馈的题目
*/
uni.$on('e-exam-paper-item-feedback', (e) => {
console.log('==== 监听纠错反馈 e-exam-paper-item-feedback :', e)
})
}
/**
* 切换题目
* @param {Object} e 当前题目
*/
function changePaper(e) {
console.log('==== 切换题目 :', e)
}
/**
* 退出考试
* @param {Object} e 做题记录,可缓存或上传云端,用作下一次打开后继续进度
*/
function onQuit(e) {
console.log('==== 退出考试 :', e)
}
onUnload(() => {
// 统一做exam所有事件监听移除操作 (尽管该页面可能未开启相关监听)
uni.$off('e-exam-paper-item-submit')
uni.$off('e-exam-paper-complete')
uni.$off('e-exam-paper-item-fav')
uni.$off('e-exam-paper-item-feedback')
})
</script>
配置中心
// 在文件目录 @/uni_modules/sv-exam/components/sv-exam/config.js 下进行相关配置
/**
* 三种答题模式 - 字段值可改,字段循序勿改,请保持 0:背题,1:刷题,2:考试 的顺序
* recite 背题模式 题库中顺序出题,带有答案,只需看题背答案,无需手动写题,可继续背题
* practice 刷题模式 题库中顺序出题,答题完自动批改对错并给出答案,可继续或重新答题
* exam 模拟考试 题库中随机抽取指定数量道题并打乱顺序,提交后自动批改,退出考试时弹出提示,时间到自动交卷
*/
examTypeDict: {
0: 'recite',
1: 'practice',
2: 'exam'
},
paperTypeDict: { // 题型字典
0: '单选题',
1: '多选题',
2: '判断题' // 判断题本质上和单选一样
},
swiperDuration: 200, // 上/下一题切换动画速度 单位ms
favThrottle: 1000, // 收藏节流时间 单位ms
favThrottleText: '收藏太频繁啦~', // 收藏节流字样
feedbackText: '答案有误?点击反馈', // 反馈提示字样
toCompleteText: '在最后一页交卷', // 去交卷提示字样
quitText: '正在考试中,确定离开吗?', // 返回提示内容
countdown: 60, // 考试倒计时 单位分钟
自定义图标
- 本插件采用阿里巴巴矢量库图标,在插件目录 @/uni_modules/sv-exam/components/sv-exam/icons 文件夹下
- 需要自定义图标时,请替换该icons文件夹iconfont.ttf文件,并修改iconfont.css中的Unicode编码(建议保留原icon-名称,例如icon-correct、icon-wrong等,只修改Unicode编码即可)
写在最后
若对插件有任何疑问或者优化建议,欢迎在评论区留言,在插件市场中的私信消息本人可能不经常留意,导致没能及时回复, 可以加入本人的插件问答QQ交流群: 852637893,欢迎进群交流。