video-player.vue 13.3 KB
<template>
  <div class="video-player">
    <video
      v-if="showVideo"
      ref="videoPlayer"
      class="video-js vjs-matrix vjs-yoho"
      :poster="coverImg"
      controls
      preload="auto"
      playsinline
      x5-playsinline
      webkit-playsinline="true">
      <source :src="source" :type="sourceType"></source>
      <p class="vjs-no-js">
        To view this video please enable JavaScript, and consider upgrading to a
        web browser
      </p>
      <div class="vjs-yoho-voice"></div>
    </video>
  </div>
</template>

<script>
import {get} from 'lodash';
import videojs from 'video.js';
import {getArticleImageSize, processImage} from 'utils/image-handler';
import versionCompare from 'utils/version';

export default {
  name: 'VideoPlayer',
  props: {
    source: String,
    cover: String,
    width: [Number, String],
    height: [Number, String],
    options: {
      type: Object,
      default() {
        return {
          muted: true,
          controls: true,
          aspectRatio: '1:1'
        };
      }
    }
  },
  data() {
    return {
      showVideo: false,
      player: null
    };
  },
  computed: {
    coverImg() {
      if (this.cover) {
        if (this.width && this.height) {
          let imgSize = getArticleImageSize({
            width: this.width,
            height: this.height,
            minScale: 0,
            maxWidth: 500
          });

          return processImage(this.cover, 2, imgSize.width, imgSize.height, get(this.yoho, 'window.supportWebp'));
        } else {
          return this.cover.split('?')[0];
        }
      } else {
        return '';
      }
    },
    sourceType() {
      let type = 'video/mp4';

      if (this.source) {
        let source = this.source.split('?')[0];

        source = source.split('.');

        switch (source[source.length - 1]) {
          case 'opus':
          case 'ogv':
            type = 'video/ogg';
            break;
          case 'mkv':
            type = 'video/x-matroska';
            break;
          case 'm3u8':
            type = 'application/x-mpegURL';
            break;
          case 'm4a':
            type = 'audio/mp4';
            break;
          case 'mp3':
            type = 'audio/mpeg';
            break;
          case 'aac':
            type = 'audio/aac';
            break;
          case 'oga':
            type = 'audio/ogg';
            break;
          default:
            break;
        }
      }

      return type;
    }
  },
  watch: {
    source() {
      this.showPlayer();
    }
  },
  mounted() {
    this.showPlayer();
  },
  beforeDestroy() {
    if (this.player) {
      this.player.dispose();
    }
  },
  methods: {
    showPlayer() {
      if (this.showVideo || !this.source) {
        return;
      }

      this.showVideo = true;
      this.$nextTick(() => {
        this.initPlayer();
      });
    },
    initPlayer() {
      const noVioceClass = 'vjs-yoho-novoice';

      this.player = videojs(this.$refs.videoPlayer, this.options);

      this.voiceBtn = this.player.addChild('button');
      this.voiceBtn.addClass('vjs-yoho-voice');
      this.voiceBtn.addClass(noVioceClass);
      this.backBtn = this.player.addChild('button');
      this.backBtn.addClass('vjs-yoho-back');
      this.voiceBtn.on('touchend', () => {
        this.player.muted(!this.voiceBtn.hasClass(noVioceClass));
      });
      this.backBtn.on('touchend', () => {
        this.player.exitFullscreen();
      });

      this.player.on('play', () => {
        this.player._yohoPlayTime = this.getTime();
      });
      this.player.on('pause', () => {
        this.player._yohoPauseTime = this.getTime();
      });
      this.player.on('ended', () => {
        this.player._yohoEndedTime = this.getTime();
      });

      this.player.on('fullscreenchange', () => {
        // ios 退出全屏自动播放
        if (this.$yoho.isiOS && versionCompare(this.$yoho.appVersion, '6.9.7') > 0) {
          let changeTime = this.getTime();
          let playTime = this.player._yohoPlayTime || 0;
          let pauseTime = this.player._yohoPauseTime || 0;
          let endedTime = this.player._yohoEndedTime || 0;

          if ((changeTime - pauseTime) < 600 && pauseTime > playTime && playTime > endedTime) {
            setTimeout(() => {
              this.player.play();
            }, 1000);
          }
        }
      });

      this.player.on('volumechange', () => {
        const soundOff = this.player.muted() || this.player.volume() === 0;

        if (soundOff) {
          this.voiceBtn.addClass(noVioceClass);
        } else {
          this.voiceBtn.removeClass(noVioceClass);
        }
      });
    },
    getTime() {
      return new Date().getTime();
    }
  }
};
</script>

<style lang="scss" scoped>
  .video-js {
    width: 100%;
    height: auto;

    video {
      width: 100%;
    }

    &.vjs-yoho /deep/ {
      position: relative;
      background-color: #222;

      .vjs-resize-manager {
        z-index: 0;
        visibility: hidden;
      }

      .vjs-poster {
        background-color: #222;
      }

      .vjs-yoho-voice {
        width: 60px;
        height: 60px;
        position: absolute;
        top: 20px;
        right: 28px;
        opacity: 0;
        visibility: hidden;
        background: url("~statics/image/components/video-voice-icon.png");
        background-size: cover;
        background-repeat: no-repeat;

        &.vjs-yoho-novoice {
          background-position: bottom left;
        }
      }

      &.vjs-has-started .vjs-yoho-voice {
        visibility: visible;
        opacity: 1;
        transition: visibility 1s, opacity 1s;
      }

      &.vjs-has-started.vjs-user-inactive.vjs-playing .vjs-yoho-voice {
        visibility: visible;
        opacity: 0;
      }

      .vjs-big-play-button {
        width: 126px;
        height: 126px;
        line-height: 126px;
        font-size: 60px;
        border: none;
        left: 50%;
        top: 50%;
        margin: -63px auto auto -63px;

        /* background: url("~statics/image/components/video-play-btn.png"); */
        background: url("data:image/png;base64,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");
        background-size: contain;
        background-repeat: no-repeat;

        > * {
          display: none;
        }
      }

      @keyframes roundframe {
        0% { -webkit-transform: rotate(0deg); }
        25% { -webkit-transform: rotate(90deg); }
        50% { -webkit-transform: rotate(180deg); }
        75% { -webkit-transform: rotate(270deg); }
        100% { -webkit-transform: rotate(360deg); }
      }

      .vjs-loading-spinner {
        width: 110px;
        height: 110px;
        margin-top: -55px;
        margin-left: -55px;
        border: none;
        background: url("~statics/image/components/video-loading-icon.png");
        background-size: contain;
        background-repeat: no-repeat;
        background-position: center center;
        visibility: visible;
        animation: roundframe 1.3s linear infinite;

        &:before,
        &:after,
        > * {
          display: none;
        }
      }

      .vjs-control-bar {
        height: 80px;
        background: none;
        padding-bottom: 20px;

        .vjs-control {
          width: 80px;
        }

        .vjs-play-control {
          width: 60px;
          height: 60px;
          margin-left: 20px;
          background: url("~statics/image/components/video-play-icon.png");
          background-size: cover;

          &.vjs-playing {
            background-position: bottom left;
          }

          > * {
            display: none;
          }
        }

        .vjs-volume-panel {
          display: none;
        }

        .vjs-duration,
        .vjs-current-time {
          display: block;
          order: 3;

          > span {
            font-size: 22px;
            font-weight: 300;
          }
        }

        .vjs-time-control {
          line-height: 60px;
        }

        .vjs-current-time {
          order: 1;
        }

        .vjs-remaining-time {
          display: none;
        }

        .vjs-progress-control {
          order: 2;

          .vjs-progress-holder {
            margin: 0;
          }

          .vjs-progress-holder,
          .vjs-load-progress,
          .vjs-play-progress {
            height: 1px;
          }

          .vjs-play-progress:before {
            font-size: 10px;
            top: 0;
            transform: translateY(-44%);
          }
        }

        .vjs-fullscreen-control {
          order: 4;
          width: 60px;
          height: 60px;
          margin-right: 20px;
          background: url("~statics/image/components/video-fullscreen-icon.png");
          background-size: cover;

          > * {
            display: none;
          }
        }

        .vjs-icon-placeholder:before {
          font-size: 38px;
          line-height: 60px;
        }
      }

      &.vjs-fullscreen .vjs-fullscreen-control {
        background-position: bottom left;
      }

      &.vjs-fullscreen .vjs-yoho-back {
        width: 40px;
        height: 42px;
        background: url("~statics/image/components/video-back-icon.png");
        background-size: contain;
        background-repeat: no-repeat;
        position: absolute;
        top: 20px;
        left: 32px;
      }
    }
  }
</style>