|
@@ -9,16 +9,45 @@
|
|
|
:src="playUrl"
|
|
:src="playUrl"
|
|
|
:poster="poster"
|
|
:poster="poster"
|
|
|
></video>
|
|
></video>
|
|
|
- <div class="video-box" :class="{ pause: !isPlaying }" @click="changePlay">
|
|
|
|
|
|
|
+ <div
|
|
|
|
|
+ class="video-box"
|
|
|
|
|
+ :class="{ pause: !isPlaying || state.dragging }"
|
|
|
|
|
+ @click="changePlay"
|
|
|
|
|
+ @touchstart="onTouchStart"
|
|
|
|
|
+ @touchmove="onTouchMove"
|
|
|
|
|
+ @touchend="onTouchEnd"
|
|
|
|
|
+ ref="boxRef"
|
|
|
|
|
+ >
|
|
|
<van-icon class="play-img" v-if="!isPlaying" size="80" color="#fff" name="play-circle" />
|
|
<van-icon class="play-img" v-if="!isPlaying" size="80" color="#fff" name="play-circle" />
|
|
|
<van-slider v-model="currentVal" @change="onChange" />
|
|
<van-slider v-model="currentVal" @change="onChange" />
|
|
|
|
|
+ <div class="top-box" v-if="isPre">
|
|
|
|
|
+ <div class="top" :style="{ top: top + 'px' }">
|
|
|
|
|
+ 上一集
|
|
|
|
|
+ <div class="top-img">
|
|
|
|
|
+ <Vue3Lottie :speed="1.2" :animationData="downJSON" />
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div class="next-box" v-if="isNext">
|
|
|
|
|
+ <div class="next" :style="{ bottom: bottom + 'px' }">
|
|
|
|
|
+ 下一集
|
|
|
|
|
+ <div class="next-img">
|
|
|
|
|
+ <Vue3Lottie :speed="1.2" :animationData="downJSON" />
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
|
</template>
|
|
</template>
|
|
|
|
|
|
|
|
<script setup>
|
|
<script setup>
|
|
|
-import { ref, onMounted, nextTick, computed, onUnmounted } from 'vue'
|
|
|
|
|
|
|
+import { ref, onMounted, nextTick, reactive, computed, onUnmounted } from 'vue'
|
|
|
import { accDiv } from '../plugins/calc'
|
|
import { accDiv } from '../plugins/calc'
|
|
|
|
|
+import { useTouch } from 'vant/lib/composables/use-touch'
|
|
|
|
|
+import { clamp } from 'vant/lib/utils'
|
|
|
|
|
+import { useRect } from '@vant/use'
|
|
|
|
|
+import { Vue3Lottie } from 'vue3-lottie'
|
|
|
|
|
+import downJSON from '@/assets/lottie/down.json'
|
|
|
const props = defineProps({
|
|
const props = defineProps({
|
|
|
playUrl: {
|
|
playUrl: {
|
|
|
type: String,
|
|
type: String,
|
|
@@ -28,16 +57,16 @@ const props = defineProps({
|
|
|
type: String,
|
|
type: String,
|
|
|
default: ''
|
|
default: ''
|
|
|
},
|
|
},
|
|
|
- curEpInfo: {
|
|
|
|
|
- type: Object,
|
|
|
|
|
- default: () => {
|
|
|
|
|
- return {}
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ isPre: {
|
|
|
|
|
+ type: Boolean,
|
|
|
|
|
+ default: false
|
|
|
|
|
+ },
|
|
|
|
|
+ isNext: {
|
|
|
|
|
+ type: Boolean,
|
|
|
|
|
+ default: false
|
|
|
}
|
|
}
|
|
|
})
|
|
})
|
|
|
|
|
|
|
|
-const emit = defineEmits(['videoEnded'])
|
|
|
|
|
-
|
|
|
|
|
const videoRef = ref(null)
|
|
const videoRef = ref(null)
|
|
|
const currentVal = ref(0)
|
|
const currentVal = ref(0)
|
|
|
const canChange = ref(true)
|
|
const canChange = ref(true)
|
|
@@ -101,9 +130,64 @@ function changePlay() {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-defineExpose({ getCurrent, play, pause, setCurrent, changeMuted })
|
|
|
|
|
|
|
+const boxRef = ref(null)
|
|
|
|
|
+const getHeightByRef = ref2 => (ref2.value ? useRect(ref2).height : 0)
|
|
|
|
|
+
|
|
|
|
|
+const state = reactive({
|
|
|
|
|
+ offset: 0,
|
|
|
|
|
+ dragging: false
|
|
|
|
|
+})
|
|
|
|
|
+const startOffset = ref(0)
|
|
|
|
|
+const touch = useTouch()
|
|
|
|
|
+const lockClick = ref(false)
|
|
|
|
|
+
|
|
|
|
|
+function onTouchStart(event) {
|
|
|
|
|
+ startOffset.value = state.offset
|
|
|
|
|
+ touch.start(event)
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+const bottom = ref(-54)
|
|
|
|
|
+const top = ref(-54)
|
|
|
|
|
+
|
|
|
|
|
+function onTouchMove(event) {
|
|
|
|
|
+ const { deltaY } = touch
|
|
|
|
|
+ touch.move(event)
|
|
|
|
|
+ if (touch.isVertical) {
|
|
|
|
|
+ lockClick.value = true
|
|
|
|
|
+ state.dragging = true
|
|
|
|
|
+ state.offset = clamp(deltaY.value + startOffset.value, -getHeightByRef(boxRef) / 2, getHeightByRef(boxRef) / 2)
|
|
|
|
|
+ console.log(state.offset)
|
|
|
|
|
+ if (state.offset < 0 && top.value == -54) {
|
|
|
|
|
+ bottom.value = 0 - state.offset - 54 > 0 ? 0 : 0 - state.offset - 54
|
|
|
|
|
+ }
|
|
|
|
|
+ if (state.offset > 0 && bottom.value == -54) {
|
|
|
|
|
+ top.value = state.offset - 54 > 0 ? 0 : state.offset - 54
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
|
|
+function onTouchEnd(event) {
|
|
|
|
|
+ if (state.dragging) {
|
|
|
|
|
+ state.dragging = false
|
|
|
|
|
+ changeSide(state.offset > 0 ? 'pre' : 'next')
|
|
|
|
|
+ }
|
|
|
|
|
+ state.offset = 0
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
|
|
+function changeSide(side) {
|
|
|
|
|
+ console.log(side)
|
|
|
|
|
+ if (bottom.value >= 0 || top.value >= 0) {
|
|
|
|
|
+ emit('changeSide', side)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ bottom.value = -54
|
|
|
|
|
+ top.value = -54
|
|
|
|
|
+
|
|
|
|
|
+ //
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+const emit = defineEmits(['videoEnded', 'changeSide'])
|
|
|
|
|
+defineExpose({ getCurrent, play, pause, setCurrent, changeMuted })
|
|
|
</script>
|
|
</script>
|
|
|
|
|
|
|
|
<style lang="less" scoped>
|
|
<style lang="less" scoped>
|
|
@@ -125,6 +209,10 @@ defineExpose({ getCurrent, play, pause, setCurrent, changeMuted })
|
|
|
transition: all ease-in-out 0.3s;
|
|
transition: all ease-in-out 0.3s;
|
|
|
&.pause {
|
|
&.pause {
|
|
|
background-color: rgba(0, 0, 0, 0.6);
|
|
background-color: rgba(0, 0, 0, 0.6);
|
|
|
|
|
+
|
|
|
|
|
+ .next {
|
|
|
|
|
+ transition: none;
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
@@ -136,6 +224,7 @@ defineExpose({ getCurrent, play, pause, setCurrent, changeMuted })
|
|
|
bottom: 0px;
|
|
bottom: 0px;
|
|
|
--van-slider-button-width: 18px;
|
|
--van-slider-button-width: 18px;
|
|
|
--van-slider-button-height: 18px;
|
|
--van-slider-button-height: 18px;
|
|
|
|
|
+ z-index: 30;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
.play-img {
|
|
.play-img {
|
|
@@ -144,4 +233,56 @@ defineExpose({ getCurrent, play, pause, setCurrent, changeMuted })
|
|
|
left: 50%;
|
|
left: 50%;
|
|
|
transform: translate(-50%, -50%);
|
|
transform: translate(-50%, -50%);
|
|
|
}
|
|
}
|
|
|
|
|
+.next-box {
|
|
|
|
|
+ position: absolute;
|
|
|
|
|
+ left: 0;
|
|
|
|
|
+ right: 0;
|
|
|
|
|
+ bottom: 0px;
|
|
|
|
|
+ overflow: hidden;
|
|
|
|
|
+ height: 54px;
|
|
|
|
|
+}
|
|
|
|
|
+.top-box {
|
|
|
|
|
+ position: absolute;
|
|
|
|
|
+ left: 0;
|
|
|
|
|
+ right: 0;
|
|
|
|
|
+ top: 0px;
|
|
|
|
|
+ overflow: hidden;
|
|
|
|
|
+ height: 54px;
|
|
|
|
|
+}
|
|
|
|
|
+.top {
|
|
|
|
|
+ position: absolute;
|
|
|
|
|
+ left: 0;
|
|
|
|
|
+ right: 0;
|
|
|
|
|
+ top: 0px;
|
|
|
|
|
+ z-index: 20;
|
|
|
|
|
+ text-align: center;
|
|
|
|
|
+ transition: bottom ease-in-out 0.3s;
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ justify-content: center;
|
|
|
|
|
+ flex-shrink: 0;
|
|
|
|
|
+ .top-img {
|
|
|
|
|
+ width: 54px;
|
|
|
|
|
+ height: 54px;
|
|
|
|
|
+ transform: translate(-10px, -10px) rotate(180deg);
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+.next {
|
|
|
|
|
+ position: absolute;
|
|
|
|
|
+ left: 0;
|
|
|
|
|
+ right: 0;
|
|
|
|
|
+ bottom: 0px;
|
|
|
|
|
+ z-index: 20;
|
|
|
|
|
+ text-align: center;
|
|
|
|
|
+ transition: bottom ease-in-out 0.3s;
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ justify-content: center;
|
|
|
|
|
+ flex-shrink: 0;
|
|
|
|
|
+ .next-img {
|
|
|
|
|
+ width: 54px;
|
|
|
|
|
+ height: 54px;
|
|
|
|
|
+ transform: translate(-10px, 12px);
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
</style>
|
|
</style>
|