| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467 | 
							- <!--
 
- * @FileDescription: 播放器
 
- * @Author: 黄琪勇
 
- * @Date:2024-04-03 18:30:09
 
- -->
 
- <template>
 
-    <div
 
-       @keydown="handleVideoKeydown"
 
-       @mousemove="handleVideoMousemove"
 
-       @click="handleVideoClick"
 
-       class="videoPlay"
 
-       :class="{ isHideController: !isShowController }"
 
-       tabindex="-1"
 
-    >
 
-       <video class="videoPlayBox" :id="videoId" preload="auto" playsinline webkit-playsinline></video>
 
-       <div class="videoController" @click.stop @touchstart.stop>
 
-          <div class="sliderSection">
 
-             <div class="timeController">{{ `${formatTime(timeController.currentTime)} / ${formatTime(timeController.duration)}` }}</div>
 
-             <n-slider
 
-                class="sliderController"
 
-                :keyboard="false"
 
-                :value="timeController.currentTimeSilder"
 
-                :tooltip="isShowController"
 
-                :step="0.01"
 
-                @update:value="handleSilderChange"
 
-                :on-dragend="handleTimeChange"
 
-                :max="timeController.duration"
 
-                :format-tooltip="(value:number) => {
 
-                      return formatTime(value)
 
-                }"
 
-             />
 
-          </div>
 
-          <div class="playController">
 
-             <div class="leftPlayController">
 
-                <img @click="handlePlay" :src="require(`./img/${playController.type === 'play' ? 'iconPause' : 'iconPlay'}.png`)" />
 
-                <img @click="handleLoop" class="loopImg" :src="require(`./img/${playController.loop ? 'iconLoopActive' : 'iconLoop'}.png`)" />
 
-                <img ref="btnSpendDom" src="./img//iconSpeed.png" />
 
-                <el-popover
 
-                   @show="handlePopoverTimeHide"
 
-                   ref="popoverSpendDom"
 
-                   :virtual-ref="btnSpendDom"
 
-                   trigger="click"
 
-                   placement="top"
 
-                   :teleported="false"
 
-                   popper-class="palySpeedPopover"
 
-                   virtual-triggering
 
-                >
 
-                   <div class="sliderSpeedCon">
 
-                      <img @click="handlePalySpeed(playController.speedStep)" src="./img/jia.png" />
 
-                      <n-slider
 
-                         class="sliderSpeed"
 
-                         :tooltip="false"
 
-                         :keyboard="false"
 
-                         :value="playController.palySpeed"
 
-                         @update:value="handlePalySpeedChange"
 
-                         vertical
 
-                         :step="playController.speedStep"
 
-                         :max="playController.maxSpeed"
 
-                         :min="playController.minSpeed"
 
-                      >
 
-                         <template #thumb>
 
-                            <div class="thumb">{{ playController.palySpeed.toFixed(1) + "X" }}</div>
 
-                         </template>
 
-                      </n-slider>
 
-                      <img @click="handlePalySpeed(-playController.speedStep)" src="./img/jian.png" />
 
-                   </div>
 
-                </el-popover>
 
-             </div>
 
-             <div class="rightPlayController">
 
-                <div class="videoName">
 
-                   <!-- <div>{{ videoName || "" }}</div> -->
 
-                </div>
 
-             </div>
 
-          </div>
 
-       </div>
 
-    </div>
 
- </template>
 
- <script setup lang="ts">
 
- import TCPlayer from "tcplayer.js"
 
- import "tcplayer.js/dist/tcplayer.min.css"
 
- import { onMounted, onUnmounted, ref, reactive, watch, toRef, watchEffect } from "vue"
 
- import { UUID } from "@/libs/tools"
 
- import { formatTime } from "./tools"
 
- import { NSlider } from "naive-ui"
 
- import { ElMessage } from "element-plus"
 
- const props = defineProps<{
 
-    disableEvents?: boolean
 
-    isShowController?: boolean
 
-    autoPlay?: boolean
 
- }>()
 
- const emits = defineEmits<{
 
-    (e: "ready"): void //播放器初始化完成
 
-    (e: "ended"): void //播放结束
 
-    (e: "playbackRate"): void //播放速度改动时候
 
- }>()
 
- const videoId = "video" + UUID()
 
- let playerVm: Record<string, any>
 
- let isReady = false // 是否初始化播放器播放器
 
- const videoName = ref("")
 
- /* 时间控制器 */
 
- const timeController = reactive({
 
-    currentTime: 0, // 当前时间
 
-    duration: 0, // 总时长
 
-    currentTimeSilder: 0,
 
-    isDrag: false
 
- })
 
- /* 播放控制器 */
 
- const btnSpendDom = ref()
 
- const popoverSpendDom = ref()
 
- let _popoverSpendTime: any
 
- // 定时隐藏
 
- function handlePopoverTimeHide() {
 
-    _popoverSpendTime && clearTimeout(_popoverSpendTime)
 
-    _popoverSpendTime = setTimeout(() => {
 
-       popoverSpendDom.value?.hide()
 
-    }, 5000)
 
- }
 
- const playController = reactive<{
 
-    type: "play" | "pause"
 
-    loop: boolean
 
-    minSpeed: number
 
-    maxSpeed: number
 
-    speedStep: number
 
-    palySpeed: number
 
- }>({
 
-    type: "pause", //play|pause
 
-    loop: false,
 
-    minSpeed: 0.5,
 
-    maxSpeed: 1.5,
 
-    speedStep: 0.1,
 
-    palySpeed: 1
 
- })
 
- watch(
 
-    () => playController.palySpeed,
 
-    () => {
 
-       // 值变化 重新计算隐藏时间
 
-       handlePopoverTimeHide()
 
-    }
 
- )
 
- /* 是否显示控制器 */
 
- const isShowController = ref(true)
 
- watchEffect(() => {
 
-    isShowController.value = props.isShowController
 
- })
 
- let _showTimer: any
 
- onMounted(() => {
 
-    initVideo()
 
- })
 
- onUnmounted(() => {
 
-    playerVm?.dispose()
 
- })
 
- /**
 
-  * 初始化播放器
 
-  */
 
- function initVideo() {
 
-    playerVm = TCPlayer(videoId, {
 
-       controls: false,
 
-       //autoplay: true,  // 自动播放前1秒暂停不了,改为loadedmetadata调用播放 实现自动播放
 
-       loop: false
 
-    })
 
-    // 初始化完成
 
-    playerVm.ready(() => {
 
-       console.log("播放器初始化完成")
 
-       isReady = true
 
-       emits("ready")
 
-    })
 
-    // 开始加载数据时
 
-    playerVm.on("loadstart", () => {
 
-       // 重新设置播放倍速  因为切换视频播放倍速会重置
 
-       playerVm.playbackRate(playController.palySpeed)
 
-    })
 
-    playerVm.on("loadedmetadata", () => {
 
-       console.log("loadedmetadata")
 
-       if (props.autoPlay) {
 
-          playerVm.play()
 
-       }
 
-    })
 
-    //总时长变化时候
 
-    playerVm.on("durationchange", () => {
 
-       timeController.duration = playerVm.duration()
 
-    })
 
-    //当前播放时间变化
 
-    playerVm.on("timeupdate", () => {
 
-       timeController.currentTime = playerVm.currentTime()
 
-       if (!timeController.isDrag) {
 
-          timeController.currentTimeSilder = timeController.currentTime
 
-       }
 
-    })
 
-    playerVm.on("play", () => {
 
-       playController.type = "play"
 
-    })
 
-    playerVm.on("pause", () => {
 
-       playController.type = "pause"
 
-    })
 
-    // 播放结束
 
-    playerVm.on("ended", () => {
 
-       emits("ended")
 
-    })
 
- }
 
- /**
 
-  * 播放  需要在ready之后调用
 
-  */
 
- // 接口请求可能在播放之前 所以这里等待播放器初始化
 
- let _time: any
 
- function playVideo({ src, name }: { src: string; name: string }) {
 
-    videoName.value = name
 
-    _time && clearInterval(_time)
 
-    if (isReady) {
 
-       handlePlayVideo(src)
 
-    } else {
 
-       _time = setInterval(() => {
 
-          if (isReady) {
 
-             clearInterval(_time)
 
-             handlePlayVideo(src)
 
-          }
 
-       }, 60)
 
-    }
 
- }
 
- function handlePlayVideo(src: string) {
 
-    playerVm?.src(src)
 
-    showController()
 
- }
 
- /* 时间控制器 */
 
- function handleTimeChange(value?: number) {
 
-    playerVm.currentTime(value || timeController.currentTimeSilder)
 
-    timeController.isDrag = false
 
- }
 
- function handleSilderChange(value: number) {
 
-    timeController.isDrag = true
 
-    timeController.currentTimeSilder = value
 
- }
 
- // 快进或者快退
 
- function speedCurrentTime(type: "fast" | "slow") {
 
-    handleTimeChange(timeController.currentTime + (type === "fast" ? 5 : -5))
 
-    showController()
 
- }
 
- /* 播放控制器 */
 
- function handlePlay() {
 
-    playController.type === "pause" ? playerVm.play() : playerVm.pause()
 
-    showController()
 
- }
 
- // 暂停
 
- function pauseVideo() {
 
-    playerVm.pause()
 
-    showController()
 
- }
 
- // 循环播放
 
- let message: any = null
 
- function handleLoop() {
 
-    playController.loop ? playerVm.loop(false) : playerVm.loop(true)
 
-    playController.loop = playerVm.loop()
 
-    if (playController.loop) {
 
-       if (message) {
 
-          message.close()
 
-       }
 
-       message = ElMessage({
 
-          message: "已打开循环播放",
 
-          icon: "",
 
-          customClass: "defaultMessage"
 
-       })
 
-    } else {
 
-       if (message) {
 
-          message.close()
 
-       }
 
-       message = ElMessage({
 
-          message: "已关闭循环播放",
 
-          icon: "",
 
-          customClass: "defaultMessage"
 
-       })
 
-    }
 
- }
 
- // 播放速度
 
- function handlePalySpeedChange(value: number) {
 
-    playController.palySpeed = value
 
-    playerVm.playbackRate(value)
 
-    emits("playbackRate")
 
- }
 
- function handlePalySpeed(value: number) {
 
-    const palySpeed = parseFloat((playController.palySpeed + value).toFixed(1))
 
-    if (palySpeed > playController.maxSpeed || palySpeed < playController.minSpeed) {
 
-       return
 
-    }
 
-    handlePalySpeedChange(palySpeed)
 
- }
 
- function handleVideoClick() {
 
-    if (props.disableEvents) return
 
-    handlePlay()
 
- }
 
- function handleVideoKeydown(e: KeyboardEvent) {
 
-    if (props.disableEvents) return
 
-    const key = e.key
 
-    if (key === " ") {
 
-       handlePlay()
 
-    } else if (key === "ArrowLeft") {
 
-       speedCurrentTime("slow")
 
-    } else if (key === "ArrowRight") {
 
-       speedCurrentTime("fast")
 
-    }
 
- }
 
- function handleVideoMousemove() {
 
-    if (props.disableEvents) return
 
-    showController()
 
- }
 
- /* 是否显示控制器 */
 
- function showController() {
 
-    if (props.disableEvents) return
 
-    isShowController.value = true
 
-    _showTimer && clearTimeout(_showTimer)
 
-    _showTimer = setTimeout(tryHideController, 3000)
 
- }
 
- function tryHideController() {
 
-    if (playController.type === "play") {
 
-       isShowController.value = false
 
-    }
 
- }
 
- defineExpose({
 
-    playVideo,
 
-    pauseVideo,
 
-    handlePlay,
 
-    speedCurrentTime,
 
-    playType: toRef(playController, "type")
 
- })
 
- </script>
 
- <style lang="scss" scoped>
 
- .videoPlay {
 
-    width: 100%;
 
-    height: 100%;
 
-    position: relative;
 
-    overflow: hidden;
 
-    :deep(.videoPlayBox) {
 
-       &.tcp-skin .tcp-right-click-popup-menu {
 
-          display: none;
 
-       }
 
-    }
 
-    .videoPlayBox {
 
-       width: 100%;
 
-       height: 100%;
 
-    }
 
-    &.isHideController {
 
-       cursor: none;
 
-       .videoController {
 
-          opacity: 0;
 
-          transform: translateY(100%);
 
-       }
 
-    }
 
-    .videoController {
 
-       position: absolute;
 
-       width: 100%;
 
-       left: 0;
 
-       bottom: 0;
 
-       padding: 45px 32px 22px;
 
-       background: linear-gradient(0deg, rgba(0, 0, 0, 0.6) 0%, rgba(0, 0, 0, 0) 100%);
 
-       color: #fff;
 
-       transition: all 0.5s;
 
-       // &:hover {   //取消鼠标移入不隐藏
 
-       //    cursor: initial;
 
-       //    opacity: initial !important;
 
-       //    transform: initial !important;
 
-       // }
 
-       .sliderSection {
 
-          display: flex;
 
-          align-items: center;
 
-          & > :deep(.sliderController.n-slider) {
 
-             --n-rail-color: rgba(255, 255, 255, 0.5) !important;
 
-             --n-fill-color: #ff8057 !important;
 
-             --n-fill-color-hover: #ff8057 !important;
 
-          }
 
-       }
 
-       .timeController {
 
-          font-weight: 500;
 
-          font-size: 20px;
 
-          color: #ffffff;
 
-          line-height: 30px;
 
-          flex-shrink: 0;
 
-          margin-right: 16px;
 
-       }
 
-       .playController {
 
-          display: flex;
 
-          justify-content: space-between;
 
-          padding-top: 4px;
 
-          .leftPlayController {
 
-             margin-left: -16px;
 
-             display: flex;
 
-             & > img {
 
-                cursor: pointer;
 
-                width: 48px;
 
-                height: 48px;
 
-                margin-right: 30px;
 
-                padding: 6px;
 
-                box-sizing: content-box;
 
-                &:hover {
 
-                   background-color: rgba(255, 255, 255, 0.2);
 
-                   border-radius: 6px;
 
-                }
 
-             }
 
-             .loopImg {
 
-                width: 56px;
 
-             }
 
-             & > :deep(.palySpeedPopover.el-popover.el-popper) {
 
-                min-width: initial;
 
-                width: 59px !important;
 
-                height: 264px;
 
-                background: url("./img/bg.png") no-repeat;
 
-                background-size: 100% 100%;
 
-                box-shadow: none;
 
-                border: none;
 
-                padding: 12px 0 20px;
 
-                .el-popper__arrow {
 
-                   display: none;
 
-                }
 
-                .sliderSpeedCon {
 
-                   width: 100%;
 
-                   height: 100%;
 
-                   display: flex;
 
-                   justify-content: center;
 
-                   align-items: center;
 
-                   flex-direction: column;
 
-                   & > img {
 
-                      cursor: pointer;
 
-                      flex-shrink: 0;
 
-                      width: 30px;
 
-                      height: 31px;
 
-                   }
 
-                   .sliderSpeed.n-slider {
 
-                      flex-grow: 1;
 
-                      padding: 6px 0;
 
-                      --n-rail-width-vertical: 5px !important;
 
-                      --n-rail-color: rgba(255, 255, 255, 0.5) !important;
 
-                      --n-fill-color: #ff8057 !important;
 
-                      --n-fill-color-hover: #ff8057 !important;
 
-                      .thumb {
 
-                         height: 22px;
 
-                         padding: 0 6px;
 
-                         background: #ffffff;
 
-                         box-shadow: 0px 2px 4px 0px rgba(102, 102, 102, 0.77);
 
-                         border-radius: 11px;
 
-                         text-align: center;
 
-                         line-height: 22px;
 
-                         font-weight: 500;
 
-                         font-size: 15px;
 
-                         color: #ff8057;
 
-                      }
 
-                   }
 
-                }
 
-             }
 
-          }
 
-          .rightPlayController {
 
-             display: flex;
 
-             align-items: center;
 
-             .videoName {
 
-                font-weight: 500;
 
-                font-size: 20px;
 
-                color: #ffffff;
 
-             }
 
-          }
 
-       }
 
-    }
 
- }
 
- </style>
 
 
  |