Commit 701804be authored by Damon's avatar Damon

refactor: 答题页面滚动组件重构

parent 1733381a
...@@ -55,12 +55,14 @@ export default { ...@@ -55,12 +55,14 @@ export default {
type: Array, type: Array,
default: [], default: [],
}, },
submitStatus: {
type: Boolean,
default: false,
},
}, },
data() { data() {
return { return {
lists: [], lists: [],
// 已提交答案
submitStatus: false,
// 答案对错 // 答案对错
answer: '', answer: '',
} }
...@@ -69,15 +71,7 @@ export default { ...@@ -69,15 +71,7 @@ export default {
answerList: { answerList: {
handler: function(newValue, oldValue) { handler: function(newValue, oldValue) {
if (newValue.length > 0) { if (newValue.length > 0) {
this.lists = newValue.map((v) => { this.lists = newValue
if (!v.checked) v.checked = false
if (!v.confirm) {
v.confirm = false
} else {
this.submitStatus = true
}
return v
})
} }
}, },
immediate: true, immediate: true,
...@@ -101,7 +95,9 @@ export default { ...@@ -101,7 +95,9 @@ export default {
}) })
this.$set(this.lists[index], 'confirm', true) this.$set(this.lists[index], 'confirm', true)
// 判断所选答案是否正确 // 判断所选答案是否正确
this.answer = this.rightKey.includes(this.lists[index].sort) ? 'pass' : 'fail' this.answer = this.rightKey.includes(this.lists[index].sort)
? 'pass'
: 'fail'
} }
this.$set(this.lists[index], 'checked', !this.lists[index].checked) this.$set(this.lists[index], 'checked', !this.lists[index].checked)
...@@ -124,7 +120,6 @@ export default { ...@@ -124,7 +120,6 @@ export default {
} }
}, },
submitAnswer() { submitAnswer() {
this.submitStatus = true
this.$emit('change', this.answer, this.lists) this.$emit('change', this.answer, this.lists)
}, },
}, },
......
...@@ -8,11 +8,12 @@ ...@@ -8,11 +8,12 @@
### Props ### Props
| 属性名 | 类型 | 默认值 | 可选值 | 说明 | | 属性名 | 类型 | 默认值 | 可选值 | 说明 |
| :--------: | :-----: | :----: | :--------: | :---------------------: | | :----------: | :-----: | :----: | :--------: | :---------------------------------------------: |
| multiple | Boolean | false | true/false | 是否支持多选 | | multiple | Boolean | false | true/false | 是否支持多选 |
| answerList | Array | [] | - | 答案列表 **格式见下文** | | submitStatus | Boolean | false | true/false | 是否已选定答案, 选定后回到该页面将不能再重新选 |
| rightKey | Array | [] | - | 正确答案 ['A'] | | answerList | Array | [] | - | 答案列表 **格式见下文** |
| rightKey | Array | [] | - | 正确答案 ['A'] |
### answerList 格式 ### answerList 格式
......
<template>
<view class="pageSwiperBox">
<view
class="pageSwiper"
:style="{
width: swiperWidth + 'px',
transform: 'translateX(' + (nowX + transX) + 'px)',
transition: !dragging ? duration + 'ms' : 'none',
}"
@touchstart="touchStart"
@touchmove="touchMove"
@touchend="touchEnd"
>
<block v-if="swiperType == 'lite'">
<view
class="pageSwiperItem"
:style="{ width: screenWidth + 'px', height: i != 1 ? 'auto' : '' }"
style="flex: 1;"
v-for="(item, i) in 3"
:key="i"
v-show="!waitShow"
>
<slot v-if="i == 1"></slot>
<view
class="pyh-pageSwiperMask"
v-show="i != 1"
@touchstart.stop="returnFalse"
@touchmove.stop.prevent="returnFalse"
@touchend.stop="returnFalse"
>
</view>
</view>
</block>
<block v-else-if="swiperType == 'static'">
<slot></slot>
</block>
</view>
</view>
</template>
<script>
export default {
name: 'pageSwiper',
props: {
swiperType: {
type: String,
default: 'lite',
},
dataLength: {
type: Number,
default: 1,
},
initIndex: {
type: Number,
default: 0,
},
duration: {
type: Number,
default: 200,
},
height: {
type: String,
default: '',
},
},
data() {
return {
swiperWidth: 3 * 375,
screenWidth: 375,
index: 0,
current: 1,
nowX: 0,
transX: 0,
dragging: true,
canMove: true,
showLoading: true,
waitShow: false,
pageTop: 0,
}
},
watch: {
dataLength(newValue, oldValue) {
if (newValue <= 1) this.canMove = false
},
},
created() {
this.index = this.initIndex
uni.getSystemInfo({
success: (res) => {
this.screenWidth = res.windowWidth
if (this.swiperType == 'lite') {
this.swiperWidth = 3 * res.windowWidth
this.nowX = -1 * this.current * this.screenWidth
} else if (this.swiperType == 'static') {
this.swiperWidth = this.dataLength * res.windowWidth
this.current = this.index
this.nowX = -1 * this.index * this.screenWidth
}
this.dragging = false
if (!this.height) {
var sQ = uni.createSelectorQuery().in(this)
var getTop = setInterval(() => {
sQ.select('.pageSwiperBox')
.boundingClientRect((data) => {
if (data) {
clearInterval(getTop)
this.pageTop = data.top
}
})
.exec()
}, 100)
}
},
})
},
methods: {
returnFalse() {},
swiperTap() {
this.$emit('swiperTap', this.current)
},
swiperTo(index) {
this.dragging = false
this.index = index
if (this.swiperType == 'lite') {
this.$emit('swiperChange', index)
} else if (this.swiperType == 'static') {
this.current = this.index
this.nowX = -1 * this.index * this.screenWidth
this.$emit('swiperChange', index)
}
if (!this.height) {
uni.pageScrollTo({
scrollTop: this.pageTop,
duration: 0,
})
}
},
touchStart(e) {
if (!this.canMove) return false
this.touchStartObj = e.mp.touches[0]
this.moveObj = null
},
touchMove(e) {
if (!this.canMove) return false
var moveObj = e.mp.touches[0]
if (!this.moveObj) {
this.moveObj = moveObj
if (Math.abs(this.moveObj.clientY - this.touchStartObj.clientY) <= 5) {
this.dragging = true
} else {
this.dragging = false
return false
}
}
if (!this.dragging) return false
var last = this.dataLength - 1
if (this.index == 0 && moveObj.clientX - this.touchStartObj.clientX > 0) {
this.dragging = false
this.$emit('endChange', 'left')
return false
} else if (
this.index == last &&
moveObj.clientX - this.touchStartObj.clientX < 0
) {
this.dragging = false
this.$emit('endChange', 'right')
return false
}
this.transX = parseInt(moveObj.clientX - this.touchStartObj.clientX)
if (moveObj.clientX < 0 || moveObj.clientX > this.screenWidth) {
this.touchEnd()
}
},
touchEnd() {
if (
Math.abs(this.transX) > this.screenWidth / 4 &&
this.canMove &&
this.dragging
) {
if (this.transX > 0) {
this.nowX += this.screenWidth
this.current--
} else {
this.nowX -= this.screenWidth
this.current++
}
var transAdd = this.transX > 0 ? false : true
var index = transAdd ? this.index + 1 : this.index - 1
this.transX = 0
this.dragging = false
this.canMove = false
setTimeout(() => {
this.canMove = true
this.$emit('swiperChange', index)
if (!this.height) {
uni.pageScrollTo({
scrollTop: this.pageTop,
duration: 0,
})
}
if (this.swiperType == 'lite') {
this.waitShow = true
this.dragging = true
this.index = index
this.current = 1
} else if (this.swiperType == 'static') {
if (transAdd) {
this.waitShow = true
this.dragging = true
}
this.index = index
}
this.nowX = -1 * this.current * this.screenWidth
setTimeout(() => {
this.waitShow = false
this.dragging = false
}, 200)
}, this.duration)
} else {
this.transX = 0
}
},
},
}
</script>
<style lang="scss">
.pageSwiperBox {
width: 100%;
overflow-x: hidden;
height: 100%;
flex: 1;
}
.pageSwiper {
width: 100%;
position: relative;
display: flex;
justify-content: flex-start;
align-items: flex-start;
flex: 1;
height: 100%;
}
.pageSwiper-wrap {
width: 100%;
display: flex;
align-items: flex-start;
min-height: 100%;
}
.pageSwiperItem {
overflow-x: hidden;
width: 750rpx;
position: relative;
}
.pyh-pageSwiperMask {
position: absolute;
top: 0;
width: 100%;
height: 100%;
}
.pyh-pageSwiperMask-text {
width: 750rpx;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
}
/* 旋转动画 */
.loadRotate {
margin-right: 10rpx;
display: inline-block;
width: 32upx;
height: 32upx;
border-radius: 50%;
border: 2upx solid #333;
border-bottom-color: transparent;
vertical-align: middle;
-webkit-animation: loadRotate 0.6s linear infinite;
animation: loadRotate 0.6s linear infinite;
}
@-webkit-keyframes loadRotate {
0% {
-webkit-transform: rotate(0deg);
}
100% {
-webkit-transform: rotate(360deg);
}
}
@keyframes loadRotate {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
</style>
...@@ -104,7 +104,7 @@ export default { ...@@ -104,7 +104,7 @@ export default {
// 那么不会走swiperChange的change方法,需要我们手动去给它加一个current,然后传出去 // 那么不会走swiperChange的change方法,需要我们手动去给它加一个current,然后传出去
if (current == this.swiperIndex) { if (current == this.swiperIndex) {
this.$emit("change", {source: "",current: index}) this.$emit("change", {source: "",current: index})
} }
}, },
immediate: true immediate: true
}, },
...@@ -132,9 +132,11 @@ export default { ...@@ -132,9 +132,11 @@ export default {
swiperChange: function (e) { swiperChange: function (e) {
let current = e.detail.current let current = e.detail.current
let lastIndex = this.swiperIndex let lastIndex = this.swiperIndex
console.log("本次:" + current + "上次:" + lastIndex)
let currentItem = this.swiperList[current] let currentItem = this.swiperList[current]
let info = {} let info = {}
info.source = e.detail.source info.source = e.detail.source
// 正向滑动,到下一个的时候 // 正向滑动,到下一个的时候
// 是正向衔接 // 是正向衔接
let isLoopPositive = current == START && lastIndex == END let isLoopPositive = current == START && lastIndex == END
...@@ -146,8 +148,6 @@ export default { ...@@ -146,8 +148,6 @@ export default {
this.swiperCurrent = lastIndex this.swiperCurrent = lastIndex
return return
} }
//let swiperChangeItem = "swiperList[" + this.getNextSwiperChangeIndex(current) + "]"
//this[swiperChangeItem] = this.getNextSwiperNeedItem(currentItem, this.list)
this.$set(this.swiperList, this.getNextSwiperChangeIndex(current), this.getNextSwiperNeedItem(currentItem, this.list)) this.$set(this.swiperList, this.getNextSwiperChangeIndex(current), this.getNextSwiperNeedItem(currentItem, this.list))
} }
...@@ -162,17 +162,15 @@ export default { ...@@ -162,17 +162,15 @@ export default {
this.swiperCurrent = lastIndex this.swiperCurrent = lastIndex
return return
} }
// let swiperChangeItem = "swiperList[" + this.getLastSwiperChangeIndex(current) + "]"
// this[swiperChangeItem] = this.getLastSwiperNeedItem(currentItem, this.list)
this.$set(this.swiperList, this.getLastSwiperChangeIndex(current), this.getLastSwiperNeedItem(currentItem, this.list)) this.$set(this.swiperList, this.getLastSwiperChangeIndex(current), this.getLastSwiperNeedItem(currentItem, this.list))
} }
if (currentItem == null) return if (currentItem == null) return
info.current = currentItem.index info.current = currentItem.index
this.$emit("change", info) this.$emit("change", info)
// 记录滑过来的位置,此值对于下一次滑动的计算很重要 // 记录滑过来的位置,此值对于下一次滑动的计算很重要
this.swiperIndex = current this.swiperIndex = current
}, },
/** /**
* 获取初始化的swiperList * 获取初始化的swiperList
*/ */
......
...@@ -10,26 +10,60 @@ ...@@ -10,26 +10,60 @@
></u-navbar> ></u-navbar>
<view class="head" v-if="type !== 3"> <view class="head" v-if="type !== 3">
<view class="u-flex tab" v-if="type === 1"> <view class="u-flex tab" v-if="type === 1">
<view :class="['tab-list', {'active': model === 1}]" @click="changeModel(1)">答题模式</view> <view
<view :class="['tab-list', {'active': model === 2}]" @click="changeModel(2)">学习模式</view> :class="['tab-list', { active: model === 1 }]"
@click="changeModel(1)"
>答题模式</view
>
<view
:class="['tab-list', { active: model === 2 }]"
@click="changeModel(2)"
>学习模式</view
>
</view> </view>
<view class="u-flex count-down" v-if="type === 2"> <view class="u-flex count-down" v-if="type === 2">
<view>倒计时:<u-count-down :timestamp="timestamp" bg-color="" :show-hours="false"></u-count-down></view> <view
>倒计时:<u-count-down
:timestamp="timestamp"
bg-color=""
:show-hours="false"
></u-count-down
></view>
</view> </view>
</view> </view>
<view class="swiper"> <view class="swiper">
<swiper-limited-load <page-swiper
ref="swiper" ref="pageSwiper"
:swiperHeight="500" :dataLength="dataLength"
:swiperDuration="swiperDuration" :initIndex="index"
:list="list" @swiperChange="swiperChange"
:current="current" @endChange="endChange"
:type="type" style="flex: 1;"
:model="model"
@answerChange="answerChange"
@change="swiperChange"
> >
</swiper-limited-load> <view class="u-flex subject">
<view class="title"
><text>{{ titleType[list[index].type - 1] }}</text
>{{ list[index].title }}</view
>
<view class="content">
<answer-sheet
ref="answerSheet"
:answerList="list[index].answerList"
:rightKey="list[index].rightKey"
:multiple="list[index].type === 3"
:submitStatus="list[index].submitStatus"
@change="answerChange"
></answer-sheet>
</view>
<view class="explain">
<answer-explanation
v-show="model === 2 || list[index].errShow"
:answer="list[index].answer"
:explain="list[index].explain"
></answer-explanation>
</view>
</view>
</page-swiper>
</view> </view>
<view class="u-flex u-row-around bottom"> <view class="u-flex u-row-around bottom">
<view class="u-flex"> <view class="u-flex">
...@@ -39,7 +73,11 @@ ...@@ -39,7 +73,11 @@
</view> </view>
</view> </view>
<view class="u-flex"> <view class="u-flex">
<view class="c-list" v-if="type === 1 || type === 3" @click="collection"> <view
class="c-list"
v-if="type === 1 || type === 3"
@click="collection"
>
<u-icon name="star" color="#5A6073" size="40"></u-icon> <u-icon name="star" color="#5A6073" size="40"></u-icon>
<text>收藏</text> <text>收藏</text>
</view> </view>
...@@ -50,7 +88,7 @@ ...@@ -50,7 +88,7 @@
</view> </view>
</view> </view>
<answer-operation-tips :show.sync="show" /> <!-- <answer-operation-tips :show.sync="show" />
<answer-complete-pop <answer-complete-pop
:numberList="[1, 2, 3]" :numberList="[1, 2, 3]"
type="fail" type="fail"
...@@ -58,7 +96,7 @@ ...@@ -58,7 +96,7 @@
@cancel="visible = false" @cancel="visible = false"
@submit="submit" @submit="submit"
> >
</answer-complete-pop> </answer-complete-pop> -->
</view> </view>
</template> </template>
...@@ -66,29 +104,33 @@ ...@@ -66,29 +104,33 @@
import swiperLimitedLoad from '@/components/swiper-limited-load/index.vue' import swiperLimitedLoad from '@/components/swiper-limited-load/index.vue'
import answerOperationTips from '@/components/answer-operation-tips/index.vue' import answerOperationTips from '@/components/answer-operation-tips/index.vue'
import answerCompletePop from '@/components/answer-complete-pop/index.vue' import answerCompletePop from '@/components/answer-complete-pop/index.vue'
import pageSwiper from '@/components/page-swiper/index.vue'
import answerSheet from '@/components/answer-sheet/index.vue'
import answerExplanation from '@/components/answer-explanation/index.vue'
const NO_PREV_PAGE = -1
const NO_NEXT_PAGE = -2
const app = getApp() const app = getApp()
export default { export default {
components: { components: {
swiperLimitedLoad, swiperLimitedLoad,
answerOperationTips, answerOperationTips,
answerCompletePop, answerCompletePop,
pageSwiper,
answerSheet,
answerExplanation,
}, },
data() { data() {
return { return {
visible: false, visible: false,
show: false, show: false,
// 1 练习 2 考试 3 每日一练 // 1 练习 2 考试 3 每日一练 4 错题记录 5 收藏记录
type: 1, type: 1,
// 1 答题模式 2 学习模式 // 1 答题模式 2 学习模式
model: 1, model: 1,
timestamp: 60 * 60, timestamp: 60 * 60,
list: [], list: [],
current: 0, index: 0,
currentIndex: 0, dataLength: 0,
swiperDuration: '0', titleType: ['单选题', '判断题', '多选题'],
} }
}, },
computed: {}, computed: {},
...@@ -174,8 +216,7 @@ export default { ...@@ -174,8 +216,7 @@ export default {
}, },
], ],
answer: 'B', answer: 'B',
explain: explain: '测试内容测试内容测试内容测试内容测试内容测试内容',
'测试内容测试内容测试内容测试内容测试内容测试内容',
index: 3, index: 3,
rightKey: ['B'], rightKey: ['B'],
}, },
...@@ -184,67 +225,66 @@ export default { ...@@ -184,67 +225,66 @@ export default {
this.requestQuestionInfo(lists) this.requestQuestionInfo(lists)
}, },
methods: { methods: {
requestQuestionInfo(lists) { swiperChange(e) {
// 初始化setData后,需要调用swiper组件的init方法 this.index = e
this.list = lists // 初始化checked confirm
this.$nextTick(() => { this.list[e].answerList = this.list[e].answerList.map((v) => {
// 比如上次答到了第20题 if (!v.checked) v.checked = false
this.$refs.swiper.init(0) if (!v.confirm) v.confirm = false
// 初始化后再把动画弄出来,否则初始的current不是0,界面会自动跳动到当前位置,体验不太好 return v
this.swiperDuration = '250'
// 全局记一下list, 答题卡页暂时就直接用了
app.globalData.questionList = lists
}) })
}, },
swiperChange(e) { endChange(type) {
let current = e.current if (type === 'left') {
this.currentIndex = current return uni.showToast({
if (current == NO_PREV_PAGE) {
uni.showToast({
title: '已经是第一题了', title: '已经是第一题了',
icon: 'none', icon: 'none',
}) })
return } else if (type === 'right') {
} return uni.showToast({
title: '已经是最后一题了',
if (current == NO_NEXT_PAGE) { icon: 'none',
uni.showModal({
title: '提示',
content: '您已经答完所有题,是否退出?',
}) })
return
} }
}, },
requestQuestionInfo(lists) {
this.list = lists
this.dataLength = lists.length
app.globalData.questionList = lists
},
changeModel(i) { changeModel(i) {
this.model = i this.model = i
}, },
collection() { collection() {
console.log("this.list[this.currentIndex]", this.list[this.currentIndex]) console.log('收藏')
console.log("收藏")
}, },
// 作答完毕 // 作答完毕
answerChange(status, lists) { answerChange(status, lists) {
// 保存答题状态 // 保存答题状态
this.$set(this.list[this.currentIndex], 'answerList', lists) this.$set(this.list[this.index], 'submitStatus', true)
this.$set(this.list[this.currentIndex], 'errShow', this.type === 2 ? true : status === 'fail') this.$set(this.list[this.index], 'answerList', lists)
this.$set(
this.list[this.index],
'errShow',
this.type === 2 ? true : status === 'fail'
)
app.globalData.questionList = this.list app.globalData.questionList = this.list
// 如果回答错误或者是考试模式,自动进入下一题 // 如果回答错误或者是考试模式,自动进入下一题
if (status === 'pass' || this.type === 2) { if (status === 'pass' || this.type === 2) {
if (this.currentIndex + 1 > this.list.length - 1) { if (this.index + 1 === this.list.length) return
return this.index++
} this.$refs.pageSwiper.swiperTo(this.index)
this.current = this.currentIndex + 1
} }
}, },
// 交卷 // 交卷
handPapers() { handPapers() {
this.visible = true this.visible = true
console.log("交卷") console.log('交卷')
}, },
// 提前交卷 // 提前交卷
submit() { submit() {
console.log("提前交卷") console.log('提前交卷')
} },
}, },
} }
</script> </script>
...@@ -260,31 +300,64 @@ export default { ...@@ -260,31 +300,64 @@ export default {
width: 100%; width: 100%;
height: 90rpx; height: 90rpx;
.tab { .tab {
margin:10rpx auto; margin: 10rpx auto;
border: 2rpx solid #2953FF; border: 2rpx solid #2953ff;
border-radius: 10rpx; border-radius: 10rpx;
width: 300rpx; width: 300rpx;
.tab-list { .tab-list {
flex: 1; flex: 1;
padding: 10rpx 25rpx; padding: 10rpx 25rpx;
font-size: 24rpx; font-size: 24rpx;
color: #191C27; color: #191c27;
} }
.active { .active {
background: #2953FF; background: #2953ff;
color: #fff; color: #fff;
} }
} }
.count-down { .count-down {
color: #5A6073; color: #5a6073;
font-size: 32rpx; font-size: 32rpx;
margin:10rpx auto; margin: 10rpx auto;
width: 230rpx; width: 230rpx;
} }
} }
.swiper { .swiper {
width: 100%; width: 100%;
flex: 1; flex: 1;
display: flex;
flex-direction: column;
.subject {
flex-flow: column;
padding: 20rpx;
.type {
width: 100%;
text-align: left;
padding: 20rpx 0;
}
.title {
color: #191c27;
font-size: 32rpx;
line-height: 50rpx;
font-weight: bold;
width: 100%;
text-align: left;
text {
background: #9ea5bb;
color: #fff;
padding: 8rpx 20rpx;
margin-right: 10rpx;
font-size: 20rpx;
border-radius: 50rpx;
}
}
.content,
.explain,
.btn {
width: 100%;
padding-top: 50rpx;
}
}
} }
.bottom { .bottom {
width: 100%; width: 100%;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment