| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269 | <template>  <view class="video-box" v-loading="loading">    <video      v-if="videoUrl"      class="video-box-body"      id="myVideo"      @timeupdate="timeUpdate"      :src="videoUrl"      controls      :initial-time="initial_time"      object-fit="fill"      play-btn-position="center"      @ended="ended"      @tap="videoClick"      @loadedmetadata="loadedmetadata"    >      <cover-view class="video-control">        <cover-view class="multi rate" @tap.stop="showSwitchRate">x {{ currentRate }}</cover-view>      </cover-view>      <cover-view class="multi-list rate" :class="{ active: rateShow }">        <cover-view          v-for="(item, index) in rateList"          :key="index"          class="multi-item rate"          :data-rate="item"          @tap="switchRate"          :class="{ active: item == currentRate }"        >          {{ item }}        </cover-view>      </cover-view>    </video>    <view class="video-box-body" v-else>      <u-empty text="视频地址为空" mode="page"></u-empty>    </view>  </view></template><script>export default {  name: 'VideoBox',  props: {    rateList: {      type: Array,      default: () => ['0.5', '1.0', '1.5', '2.0']    },    videoUrl: {      type: String,      default: ''    }  },  data() {    return {      // 加载层      loading: false,      // 视频创建dom      videoContext: uni.createVideoContext('myVideo', this),      // 视频实时时间      initial_time: 0,      // 视频已经播放时间      playedTime: 0,      // 倍速浮层      rateShow: false,      // 默认倍速      currentRate: 1.0,      // 视频实际时间      video_real_time: 0,      // 视频总时长      duration: 0,      // 当前视频选中播放      currentDuration: 0,      // 视频信息      videoInfo: {},      // 选中课程下标      videoIndex: 0    };  },  methods: {    /**     * 加载视频     * @date 2022-10-19     * @returns {any}     */    loadVideo(data) {      this.loading = true;      this.videoInfo = data;      this.initial_time = Number(data.currentDuration);      this.video_real_time = Number(data.playDuration);      this.playedTime = Number(data.playDuration);    },    /**     * 记录时间     * @date 2022-10-19     * @param { Number } index     * @returns {any}     */    recordDuration(index, refresh) {      this.videoIndex = index;      let playDuration = this.video_real_time;      if (this.videoInfo.playDuration > this.video_real_time) {        this.currentDuration = this.video_real_time;        playDuration = this.videoInfo.playDuration;      } else {        this.currentDuration = this.video_real_time;      }      this.$emit('recordDuration', { playDuration, duration: this.duration, currentDuration: this.currentDuration }, index, refresh);    },    /**     * 获取视频总时长     * @param {Object} data     */    loadedmetadata(data) {      this.duration = data.detail.duration;      this.loading = false;    },    /**     * 显示倍速浮层     * @date 2022-10-19     * @returns {any}     */    showSwitchRate() {      this.rateShow = true;    },    /**     * 切换倍速     * @param {Object} e     */    switchRate(e) {      let rate = Number(e.currentTarget.dataset.rate);      this.currentRate = rate;      this.rateShow = false;      this.videoContext.playbackRate(rate);    },    /**     * 视频点击     * @param {Object} e     */    videoClick(e) {      this.rateShow = false;    },    /**     * 视频停止     * @date 2022-10-19     * @param {any} e     * @returns {any}     */    pause(e) {      console.log(e);    },    /**     * 控制视频不能快进     * @param {Object} e     */    timeUpdate(e) {      //播放的总时长      let duration = e.detail.duration;      //实时播放进度 秒数      let jumpTime = parseInt(e.detail.currentTime);      //当前视频进度      if (jumpTime - this.playedTime > 3) {        // 差别过大,调用seek方法跳转到实际观看时间        this.videoContext.seek(this.playedTime);        wx.showToast({          title: '未完整看完该视频,不能快进',          icon: 'none',          duration: 2000        });      } else {        this.video_real_time = parseInt(e.detail.currentTime);        this.currentDuration = e.detail.currentTime        if (this.video_real_time > this.playedTime) {          this.playedTime = this.video_real_time;        }      }    },    /**     * 视频结束     */    ended() {      // 用户把进度条拉到最后,但是实际观看时间不够,跳转回去会自动暂停。      // 这里加个判断。      this.$emit(        'recordDuration',        { playDuration: this.playedTime, duration: this.duration, currentDuration: this.currentDuration },        this.videoIndex,        false      );    }  }};</script><style lang="scss" scoped>.video-box {  &-body {    width: 100%;    height: 400rpx;    .video-control {      background-color: rgba(0, 0, 0, 0.1);      height: 90rpx;      position: absolute;      top: 0;      left: 0;      width: 100%;      z-index: 997;    }    .video-wrap {      position: relative;    }    .multi-list.full-screen.vertical {      height: 100vh !important;      padding: 8vh 0;    }    .multi-list.full-screen.horizontal {      height: 100vw !important;      padding: 8vw 0;    }    .multi {      position: absolute;      right: 30rpx;      top: 50%;      transform: translateY(-50%);      z-index: 998;      width: 100rpx;      color: #fff;      padding: 10rpx 0;      text-align: center;      transition: color ease 0.3s;    }    .multi.rate {      right: 30rpx;    }    .multi-list {      position: absolute;      height: 100%;      width: 0;      background-color: rgba(0, 0, 0, 0.65);      top: 0;      right: 0;      transition: width 0.3s ease;      z-index: 999;      box-sizing: border-box;      padding: 20rpx 0;    }    .multi-list.rate {      padding: 25rpx 0;    }    .multi-list.active {      width: 200rpx;    }    .multi-item {      text-align: center;      color: #fff;      line-height: 80rpx;      transition: color ease 0.3s;    }    .multi-item.rate {      line-height: 70rpx;    }    .multi-item:hover,    .multi:hover {      color: #00d8ff;    }    .multi-item.active {      color: #00d8ff;    }  }}</style>
 |