ソースを参照

上下集切换

panhui 2 年 前
コミット
9ed7765871
3 ファイル変更177 行追加14 行削除
  1. 0 0
      src/assets/lottie/down.json
  2. 151 10
      src/components/VideoPlayer.vue
  3. 26 4
      src/views/VideoPage.vue

ファイルの差分が大きいため隠しています
+ 0 - 0
src/assets/lottie/down.json


+ 151 - 10
src/components/VideoPlayer.vue

@@ -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>

+ 26 - 4
src/views/VideoPage.vue

@@ -26,7 +26,10 @@
                 ref="videoRef"
                 ref="videoRef"
                 :playUrl="curEpInfo.playUrl"
                 :playUrl="curEpInfo.playUrl"
                 :poster="poster"
                 :poster="poster"
+                :isPre="isPre"
+                :isNext="isNext"
                 @videoEnded="videoEnded"
                 @videoEnded="videoEnded"
+                @changeSide="changeSide"
             ></video-player>
             ></video-player>
 
 
             <div class="right-fixed">
             <div class="right-fixed">
@@ -74,7 +77,7 @@
 </template>
 </template>
 <script setup>
 <script setup>
 import { useRouter } from 'vue-router'
 import { useRouter } from 'vue-router'
-import { ref, reactive, onUnmounted, onMounted } from 'vue'
+import { ref, computed, reactive, onUnmounted, onMounted } from 'vue'
 import moreImg from '@/assets/icon_inter_white.png'
 import moreImg from '@/assets/icon_inter_white.png'
 import VideoHistory from '../components/VideoHistory.vue'
 import VideoHistory from '../components/VideoHistory.vue'
 import VideoBuy from '../components/VideoBuy.vue'
 import VideoBuy from '../components/VideoBuy.vue'
@@ -231,14 +234,33 @@ async function saveHistories(time) {
 }
 }
 
 
 function videoEnded() {
 function videoEnded() {
-    getEpisodes(curEpInfo.value.episodeNum + 1).then(() => {
-        saveHistories(videoRef.value.getCurrent())
-    })
+    if (curEpInfo.value.episodeNum !== seriesInfo.value.playCount) {
+        getEpisodes(curEpInfo.value.episodeNum + 1).then(() => {
+            saveHistories(videoRef.value.getCurrent())
+        })
+    }
 }
 }
 
 
 function playVideo(num) {
 function playVideo(num) {
     getEpisodes(num, 0)
     getEpisodes(num, 0)
 }
 }
+
+function changeSide(side) {
+    if (side === 'next') {
+        videoEnded()
+    } else if (curEpInfo.value.episodeNum > 1) {
+        getEpisodes(curEpInfo.value.episodeNum - 1).then(() => {
+            saveHistories(videoRef.value.getCurrent())
+        })
+    }
+}
+
+const isPre = computed(() => {
+    return curEpInfo.value.episodeNum > 1
+})
+const isNext = computed(() => {
+    return curEpInfo.value.episodeNum !== seriesInfo.value.playCount
+})
 </script>
 </script>
 
 
 <style lang="less" scoped>
 <style lang="less" scoped>

この差分においてかなりの量のファイルが変更されているため、一部のファイルを表示していません