移动端H5 - videojs自己设置constro样式,css全屏旋转,不唤起移动端自带的播放器

videojs自己设置constro样式

效果图

在这里插入图片描述

下载videojs插件

npm install video.js --save

引入videojs插件

import videojs from "video.js";
import "video.js/dist/video-js.css";
import "videojs-contrib-hls";

htlm部分

<div class="videoIndex" :style="{ height }">
    <div class="videoBox">
      <video
        ref="videoRef"
        class="videoCss"
        style="height: 100%; width: 100%"
        h5-playsinline
        x5-video-player-fullscreen="true"
        webkit-playsinline="true"
        playsinline="true"
      ></video>
      <div class="controlBox" v-show="isControls">
        <div class="playBackBox">
          <img
            class="playBack"
            @click.stop="setPlayStatus(true)"
            v-show="!playStatus"
            src="../../assets/images/zt.svg"
            alt=""
          />
          <img
            class="playBack"
            @click.stop="setPlayStatus(false)"
            v-show="playStatus"
            src="../../assets/images/play.svg"
            alt=""
          />
        </div>
        <div class="sliderBackBox" v-if="liveStatus == 'liveBack'">
          <div class="curAllTime">
            {{ handleVideoDuration(currentTime) }}
          </div>
          <div class="sliderBox" v-if="orientation == 'portrait'">
            <van-slider
              active-color="#FF9201"
              inactive-color="#000"
              bar-height="3px"
              v-model="sliderValue"
              @change.self="changeSlider"
            />
          </div>
          <div class="sliderBoxLandscape" v-if="orientation == 'landscape'">
            <van-slider
              vertical
              active-color="#FF9201"
              inactive-color="#000"
              bar-height="3px"
              v-model="sliderValue"
              @change="changeSlider"
            />
          </div>
          <div class="curAllTime">
            {{ handleVideoDuration(allTime) }}
          </div>
          <div class="speed" @click="speedShow = !speedShow">
            {{ speed }}
          </div>
        </div>
        <div class="rotateBox">
          <img @click.stop="isLandscape" src="../../assets/images/lan.svg" />
        </div>
      </div>
      <div class="speedBox" v-show="speedShow">
        <div
          class="speedNum"
          v-for="item in speedActions"
          :key="item.key"
          @click.stop="setSpeend(item.key)"
        >
          {{ item.name }}
        </div>
      </div>
    </div>
  </div>

js部分

export default {
  name: "MyVideo",
  props: {
    liveStatus: {
      type: String,
      default: "",
      required: true,
    },
    videoSource: {
      type: String,
      default: "",
    },
    autoplay: {
      type: Boolean,
      default: false,
    },
    isControls: {
      type: Boolean,
      default: true,
    },
    height: {
      type: String,
      default: "200px",
    },
  },
  data() {
    return {
      showPopover: false,
      speedActions: [
        { name: "0.5X", key: "0.5" },
        { name: "1.0X", key: "1" },
        { name: "1.25X", key: "1.25" },
        { name: "1.5X", key: "1.5" },
        { name: "2.0X", key: "2.0" },
      ],
      speed: "倍速",
      speedShow: false,
      player: null,
      playStatus: false,
      orientation: "portrait",
      sliderValue: 0,
      currentTime: "00:00:00",
      allTime: "00:00:00",
      sliderValue: 0,
      mediaStream: null,
      isEnd:'start'
    };
  },
  mounted() {
    const options = {
      autoplay: false,
      controls: false,
      aspectRatio: "16:9",
      muted: false,
      preload: "auto",
      sources: [
        {
          //流
          src: this.videoSource,
          type: this.liveStatus == "liveIn" ? "application/x-mpegURL" : "",
        },
      ],
    };
    this.player = videojs(this.$refs.videoRef, options, () => {});

    this.player.on("loadedmetadata", this.getFirstFrame);
    this.player.on("timeupdate", this.updateProgress);
    // 添加播放开始事件监听器
    this.player.on('play', this.onPlay);
    // 添加暂停事件监听器
    this.player.on('pause', this.onPause);
    // 添加结束事件监听器
    this.player.on('ended', this.onEnded);
  },
  created() {},
  methods: {
    onPlay() {
      this.playStatus = true;
      this.$emit('playStatus',this.playStatus)
      // 在这里可以执行您想要的操作,比如更新播放状态、显示提示信息等
    },
    onPause() {
      this.playStatus = false;
      this.$emit('playStatus',this.playStatus)
      // 在这里可以执行您想要的操作,比如暂停相关处理、显示提示信息等
    },
    handleVideoDuration(duration) {
      duration = duration || 0;
      return (
        "" +
        this.formatZero(~~(duration / 60 / 60)) +
        ":" +
        this.formatZero(~~(duration / 60) % 60) +
        ":" +
        this.formatZero(~~(duration % 60))
      );
    },
    formatZero(time) {
      return time > 9 ? time : "0" + time;
    },
    updateProgress() {
      this.currentTime = this.player.currentTime();
      this.sliderValue = (this.player.currentTime() / this.allTime) * 100;
      if (this.sliderValue == 100) {
        this.setPlayStatus(false);
      }
    },
    getFirstFrame() {
      this.allTime = this.player.duration();
      const videoElement = this.player.el().getElementsByTagName('video')[0]; // 从播放器获取HTML视频元素
      const canvas = document.createElement('canvas');
      canvas.width = videoElement.videoWidth;
      canvas.height = videoElement.videoHeight;
      const context = canvas.getContext('2d');
      setTimeout(() => {
        context.drawImage(videoElement, 0, 0, canvas.width, canvas.height);
        let firstFrame = canvas.toDataURL();
        this.player.setAttribute("poster", firstFrame);
      }, 100);
    },
    isLandscape() {
      let el = document.querySelector(".videoBox");
      if (this.orientation == "portrait") {
        this.orientation = "landscape";
        el.style.width = "100vh";
        el.style.height = "100vw";
        el.style.position = "relative";
        let isNewIphone =
          window &&
          window.screen.height >= 812 &&
          window.devicePixelRatio >= 2 &&
          !this.android;
        el.style.top = "0";
        el.style.left = "0";
        el.style.zIndex = 99;
        el.style.transform = "translateZ(100px)";
        let w = document.body.clientWidth;
        let h = document.body.clientHeight;
        let cha = Math.abs(h - w) / 2;
        el.style["transform"] =
          "translate(-" + cha + "px," + cha + "px) rotate(90deg)";
        el.style["-ms-transform"] =
          "translate(-" + cha + "px," + cha + "px) rotate(90deg)";
        el.style["-moz-transform"] =
          "translate(-" + cha + "px," + cha + "px) rotate(90deg)";
        el.style["-webkit-transform"] =
          "translate(-" + cha + "px," + cha + "px) rotate(90deg)";
        el.style["-o-transform"] =
          "translate(-" + cha + "px," + cha + "px) rotate(90deg)";
      } else if (this.orientation == "landscape") {
        this.orientation = "portrait";
        el.style.width = "100%";
        el.style.height = this.height;
        el.style.position = "relative";
        el.style.top = 0; //刘海屏回置
        el.style.transform = "none";
        el.style.zIndex = 1;
        el.style.transform = "translateZ(100px)";
      }
    },
    changeSlider(value) {
      this.player.currentTime((this.allTime / 100) * value);
    },
    setPlayStatus(val) {
      this.playStatus = val;
      if (val) {
        this.player.play();
      } else {
        this.player.pause();
      }
    },
    setSpeend(key) {
      this.speed = key == "1" ? "倍速" : key + "X";
      this.player.ready(function () {
        this.playbackRate(parseFloat(key));
      });
      this.speedShow = false;
    },
  },
  beforeDestroy() {
    if (this.player) {
      this.player.dispose();
    }
  },
};

css部分

.videoIndex {
  width: 100%;
  color: #000;
  pointer-events: none;
  .videoBox {
    height: 100%;
    display: flex;
    position: relative;
    .videoCss {
      background: #000;
      object-fit: cover;
    }
    ::v-deep .vjs-fluid:not(.vjs-audio-only-mode) {
      padding-top: 0 !important;
    }
  }
  .controlBox {
    width: 94%;
    height: 43px;
    position: absolute;
    bottom: 0;
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 0 3%;
    pointer-events: auto;
    background-image: linear-gradient(
      180deg,
      rgba(0, 0, 0, 0) 0%,
      rgba(0, 0, 0, 0.3) 99%
    );
    .playBackBox {
      width: 20px;
      height: 20px;
    }
    .sliderBackBox {
      flex: 1;
      display: flex;
      justify-content: space-between;
      align-items: center;
      .curAllTime {
        font-size: 14px;
        color: #fff;
        margin: 0 6px;
      }
      .speed {
        width: 40px;
        font-size: 14px;
        color: #fff;
        margin-right: 6px;
      }
      .sliderBox {
        flex: 1;
        margin: 0 8px;
      }
      .sliderBoxLandscape {
        height: calc(100vh - 350px);
        transform: rotate(-90deg);
        margin-left: 130px;
        margin-right: 130px;
      }
    }
    .rotateBox {
      width: 20px;
      height: 20px;
      img {
        width: 100%;
        height: 100%;
      }
    }
    ::v-deep .van-slider__button {
      width: 10px;
      height: 10px;
    }
  }
  .speedBox {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    color: #fff;
    width: 30%;
    background: rgba(0, 0, 0, 0.8);
    text-align: center;
    border-radius: 4px;
    pointer-events: auto;
  }
}
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值