liushengqiang 1 year ago
parent
commit
0e87bfc9a5

+ 150 - 0
src/views/coursewarePlay/component/video-item/index.module.less

@@ -0,0 +1,150 @@
+.videoWrap {
+  position: relative;
+  width: 100%;
+  height: 100%;
+}
+
+.content {
+  position: relative;
+  height: 100%;
+}
+
+.contentWrap {
+  height: 100%;
+
+  video {
+    width: 100%;
+    height: 100%;
+  }
+}
+
+.videoSection {
+  position: absolute;
+  top: 0;
+  left: 0;
+  right: 0;
+  bottom: 0;
+}
+
+.controls {
+  position: absolute;
+  left: 0;
+  bottom: 0;
+  right: 0;
+  height: 80px;
+  background: linear-gradient(0deg, rgba(0, 0, 0, 0.5), transparent);
+  display: flex;
+  flex-direction: column;
+  justify-content: space-between;
+  transition: all 0.5s;
+
+  &.hide {
+    transform: translateY(100%);
+  }
+
+  .time {
+    display: flex;
+    justify-content: space-between;
+    width: 100%;
+    color: #fff;
+    font-size: 10px;
+    padding: 4px 20px;
+  }
+
+  .slider {
+    width: 100%;
+    padding: 0 20px;
+
+    :global {
+      .n-slider {
+        --n-handle-size: 13px !important;
+        --n-fill-color: var(--van-primary-color) !important;
+        --n-fill-color-hover: var(--van-primary-color) !important;
+      }
+
+      .van-loading {
+        width: 100%;
+        height: 100%;
+      }
+    }
+  }
+
+  .actions {
+    display: flex;
+    width: 100%;
+    color: #fff;
+    font-size: 12px;
+    padding: 0 20px;
+    align-items: center;
+
+    .actionWrap {
+      display: flex;
+    }
+
+    .actionBtn {
+      display: flex;
+      width: 28px;
+      height: 28px;
+      padding: 4px 0;
+      background: transparent;
+    }
+
+    .actionBtn>img {
+      width: 100%;
+      height: 100%;
+    }
+
+    :global {
+      .van-loading__circular {
+        width: 100%;
+        height: 100%;
+      }
+    }
+
+    .playIcon {
+      display: none;
+    }
+
+    .btnPlay img:nth-child(2) {
+      display: block;
+    }
+
+    .btnPause img:nth-child(3) {
+      display: block;
+    }
+
+    .btnPlay,
+    .btnPause {
+      :global {
+        .van-loading {
+          display: none;
+        }
+      }
+    }
+
+    .loopBtn {
+      :global {
+        .loop {
+          display: block;
+        }
+
+        .loopActive {
+          display: none;
+        }
+      }
+    }
+
+    .loopBtn.active {
+      :global {
+        .loop {
+          display: none;
+        }
+
+        .loopActive {
+          display: block;
+        }
+      }
+    }
+
+  }
+}

+ 167 - 0
src/views/coursewarePlay/component/video-item/index.tsx

@@ -0,0 +1,167 @@
+import { defineComponent, onMounted, reactive, toRefs, watch } from 'vue'
+import { ref } from 'vue'
+import styles from './index.module.less'
+
+import iconLoop from '../../image/icon-loop.svg'
+import iconLoopActive from '../../image/icon-loop-active.svg'
+import iconplay from '../../image/icon-play.svg'
+import iconpause from '../../image/icon-pause.svg'
+import { NSlider } from 'naive-ui'
+import { getSecondRPM } from '@/helpers/utils'
+
+export default defineComponent({
+  name: 'video-play',
+  props: {
+    item: {
+      type: Object,
+      default: () => {
+        return {}
+      }
+    },
+    pageVisibility: {
+      type: String,
+      default: ''
+    },
+    show: {
+      type: Boolean,
+      default: false
+    },
+    showModel: {
+      type: Boolean,
+      default: false
+    },
+    isEmtry: {
+      type: Boolean,
+      default: false
+    }
+  },
+  emits: ['loadedmetadata', 'togglePlay', 'ended', 'reset', 'close', 'error'],
+  setup(props, { emit, expose }) {
+    const videoItem = ref()
+    const { item, isEmtry } = toRefs(props)
+    const data = reactive({
+      timer: null as any,
+      currentTime: 0,
+      duration: 0,
+      loop: false,
+      playState: 'pause' as 'play' | 'pause',
+      vudio: null as any,
+      reload: false
+    })
+    const contetRef = ref()
+
+    // watch(
+    //   () => props.show,
+    //   () => {
+    //     onToggleAudio('pause')
+    //   }
+    // )
+
+    let playTimer = null as any
+    // 切换音频播放
+    const onToggleAudio = (state: 'play' | 'pause') => {
+      clearTimeout(playTimer)
+      if (state === 'play') {
+        playTimer = setTimeout(() => {
+          videoItem.value?.play()
+          data.playState = 'play'
+        }, 100)
+      } else {
+        videoItem.value?.pause()
+        data.playState = 'pause'
+      }
+      emit('togglePlay', data.playState)
+    }
+
+    /** 改变播放时间 */
+    const handleChangeTime = (val: number) => {
+      data.currentTime = val
+      clearTimeout(data.timer)
+      data.timer = setTimeout(() => {
+        videoItem.value.currentTime = val;
+        data.timer = null;
+      }, 300)
+    }
+
+    const handleLoadedmetadata = () => {
+      data.reload = false
+      // 获取时长
+      data.duration = videoItem.value.duration()
+
+      emit('loadedmetadata', videoItem.value)
+    }
+    const onTimeupdate = () => {
+      if (data.timer) return
+      data.currentTime = videoItem.value.currentTime()
+    }
+    const onEnded = () => {
+      data.playState = 'pause'
+      emit('ended')
+    }
+    const onPaused = () => {
+      data.playState = 'pause'
+    }
+    const onPlaying = () => {
+      data.playState = 'play'
+    }
+    return () => (
+      <div class={styles.videoWrap}>
+        <div class={styles.content}>
+          <div ref={contetRef} class={styles.contentWrap}>
+            <video
+              ref={videoItem}
+              style={{ width: '100%', height: '100%' }}
+              poster={props.item.coverImg}
+              src={isEmtry.value ? '' : item.value.content}
+              preload="auto"
+              playsinline
+              webkit-playsinline
+              onLoadedmetadata={handleLoadedmetadata}
+              onTimeupdate={onTimeupdate}
+              onEnded={onEnded}
+              onPause={onPaused}
+              onPlaying={onPlaying}
+            ></video>
+          </div>
+          <div class={styles.videoSection}></div>
+        </div>
+
+        <div
+          class={[styles.controls, props.showModel ? '' : styles.hide]}
+          onClick={(e: Event) => {
+            e.stopPropagation()
+          }}
+          onTouchmove={(e: TouchEvent) => {
+            emit('close')
+          }}
+        >
+          <div class={styles.time}>
+            <div>{getSecondRPM(data.currentTime)}</div>
+            <div>{getSecondRPM(data.duration)}</div>
+          </div>
+          <div class={styles.slider}>
+            <NSlider
+              tooltip={false}
+              step={0.01}
+              class={styles.timeProgress}
+              value={data.currentTime}
+              max={data.duration}
+              onUpdate:value={(val) => handleChangeTime(val)}
+            />
+          </div>
+          <div class={styles.actions} onClick={() => emit('close')}>
+            <div
+              class={styles.actionBtn}
+              onClick={() => onToggleAudio(data.playState === 'pause' ? 'play' : 'pause')}
+            >
+              <img src={data.playState === 'pause' ? iconplay : iconpause} />
+            </div>
+            <div class={styles.actionBtn} onClick={() => (data.loop = !data.loop)}>
+              <img src={data.loop ? iconLoopActive : iconLoop} />
+            </div>
+          </div>
+        </div>
+      </div>
+    )
+  }
+})

+ 1 - 1
src/views/coursewarePlay/component/video-play.tsx

@@ -114,7 +114,7 @@ export default defineComponent({
       })
       if (videoItem.value) {
         videoItem.value.on('play', () => {
-          if (videoItem.value) {
+          if (videoItem.value && videoItem.value.muted) {
             videoItem.value.muted = false
             videoItem.value.volume = 1
           }

+ 43 - 57
src/views/coursewarePlay/index.tsx

@@ -70,17 +70,10 @@ export default defineComponent({
   name: 'CoursewarePlay',
   setup() {
     const pageVisibility = usePageVisibility()
-    const isPlay = ref(false)
     /** 页面显示和隐藏 */
     watch(pageVisibility, (value) => {
-      const activeItem = data.itemList[popupData.activeIndex]
-      if (activeItem.type != 'VIDEO') return
       if (value == 'hidden') {
-        isPlay.value = !activeItem.videoEle?.paused
-        togglePlay(activeItem, false)
-      } else {
-        // 页面显示,并且
-        if (isPlay.value) togglePlay(activeItem, true)
+        handleStop()
       }
     })
     /** 设置播放容器 16:9 */
@@ -445,19 +438,16 @@ export default defineComponent({
 
     /**停止所有的播放 */
     const handleStop = () => {
-      for (let i = 0; i < data.itemList.length; i++) {
-        const activeItem = data.itemList[i]
-
-        if (activeItem.type === 'VIDEO') {
-          activeItem.videoEle?.pause()
-          activeItem.videoEle?.stop()
-        }
-        // console.log('🚀 ~ activeItem:', activeItem)
-        // 停止曲谱的播放
-        if (activeItem.type === 'SONG') {
-          activeItem.iframeRef?.contentWindow?.postMessage({ api: 'setPlayState' }, '*')
-        }
+      const videos = document.querySelectorAll('video')
+      for (let i = 0; i < videos.length; i++) {
+        const videoEle = videos[i] as HTMLVideoElement
+        videoEle.pause()
       }
+      data.itemList.forEach((item: any) => {
+        if (item.type === 'SONG') {
+          item.iframeRef?.contentWindow?.postMessage({ api: 'setPlayState' }, '*')
+        }
+      })
     }
     // 切换素材
     const toggleMaterial = (itemActive: any) => {
@@ -592,40 +582,41 @@ export default defineComponent({
       if (popupData.activeIndex == index) return
       handleStop()
       clearTimeout(acitveTimer.value)
-      const oldIndex = popupData.activeIndex
       checkedAnimation(popupData.activeIndex, index)
-      popupData.activeIndex = index
-
-      acitveTimer.value = setTimeout(
-        () => {
-          popupData.playIndex = index
-          const item = data.itemList[index]
-          if (item) {
-            popupData.tabActive = item.knowledgePointId
-            popupData.itemActive = item.id
-            popupData.itemName = item.name
-            popupData.tabName = item.tabName
-            if (item.type == 'SONG') {
-              activeData.model = true
+      nextTick(() => {
+        popupData.activeIndex = index
+
+        acitveTimer.value = setTimeout(
+          () => {
+            popupData.playIndex = index
+            const item = data.itemList[index]
+            if (item) {
+              popupData.tabActive = item.knowledgePointId
+              popupData.itemActive = item.id
+              popupData.itemName = item.name
+              popupData.tabName = item.tabName
+              if (item.type == 'SONG') {
+                activeData.model = true
+              }
             }
-          }
-          requestAnimationFrame(() => {
-            const _effectIndex = effectIndex.value + 1
-            effectIndex.value = _effectIndex >= effects.length - 1 ? 0 : _effectIndex
+            requestAnimationFrame(() => {
+              const _effectIndex = effectIndex.value + 1
+              effectIndex.value = _effectIndex >= effects.length - 1 ? 0 : _effectIndex
 
-            if (item && item.type === 'VIDEO') {
-              // 自动播放下一个视频
-              clearTimeout(activeData.timer)
-              closeToast()
-              item.autoPlay = true
-              nextTick(() => {
-                item.videoEle?.play()
-              })
-            }
-          })
-        },
-        activeData.isAnimation ? 800 : 0
-      )
+              if (item && item.type === 'VIDEO') {
+                // 自动播放下一个视频
+                clearTimeout(activeData.timer)
+                closeToast()
+                item.autoPlay = true
+                nextTick(() => {
+                  item.videoEle?.play()
+                })
+              }
+            })
+          },
+          activeData.isAnimation ? 800 : 0
+        )
+      })
     }
 
     const onChangeSwiper = useDebounceFn((type: string, itemActive?: any) => {
@@ -774,7 +765,7 @@ export default defineComponent({
                       }, 300)
                     }}
                   >
-                    {isRender && m.type === 'VIDEO' && (
+                    {m.type === 'VIDEO' && (
                       <>
                         <VideoPlay
                           ref={(v: any) => (data.videoRefs[mIndex] = v)}
@@ -826,11 +817,6 @@ export default defineComponent({
                         }}
                       />
                     )}
-                    {!isRender && (
-                      <div class={styles.loadWrap}>
-                        <Vue3Lottie animationData={playLoadData}></Vue3Lottie>
-                      </div>
-                    )}
                   </div>
                 ) : (
                   ''