|  | @@ -1,17 +1,15 @@
 | 
	
		
			
				|  |  | -import { defineComponent, PropType } from 'vue';
 | 
	
		
			
				|  |  | -import styles from './index.module.less';
 | 
	
		
			
				|  |  | -import Plyr from 'plyr';
 | 
	
		
			
				|  |  | +import { defineComponent, nextTick, onMounted, toRefs } from 'vue';
 | 
	
		
			
				|  |  |  import 'plyr/dist/plyr.css';
 | 
	
		
			
				|  |  | -import { browser } from '@/helpers/utils';
 | 
	
		
			
				|  |  | +import Plyr from 'plyr';
 | 
	
		
			
				|  |  | +import { ref } from 'vue';
 | 
	
		
			
				|  |  | +import styles from './index.module.less';
 | 
	
		
			
				|  |  | +import iconplay from '@views/attend-class/image/icon-pause.svg';
 | 
	
		
			
				|  |  | +import iconpause from '@views/attend-class/image/icon-play.svg';
 | 
	
		
			
				|  |  | +import iconReplay from '@views/attend-class/image/icon-replay.svg';
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  export default defineComponent({
 | 
	
		
			
				|  |  | -  name: 'o-video',
 | 
	
		
			
				|  |  | +  name: 'video-play',
 | 
	
		
			
				|  |  |    props: {
 | 
	
		
			
				|  |  | -    setting: {
 | 
	
		
			
				|  |  | -      type: Object,
 | 
	
		
			
				|  |  | -      default: () => ({})
 | 
	
		
			
				|  |  | -    },
 | 
	
		
			
				|  |  | -    controls: Boolean,
 | 
	
		
			
				|  |  | -    height: String,
 | 
	
		
			
				|  |  |      src: {
 | 
	
		
			
				|  |  |        type: String,
 | 
	
		
			
				|  |  |        default: ''
 | 
	
	
		
			
				|  | @@ -20,130 +18,132 @@ export default defineComponent({
 | 
	
		
			
				|  |  |        type: String,
 | 
	
		
			
				|  |  |        default: ''
 | 
	
		
			
				|  |  |      },
 | 
	
		
			
				|  |  | -    styleValue: {
 | 
	
		
			
				|  |  | -      type: Object,
 | 
	
		
			
				|  |  | -      default: () => ({})
 | 
	
		
			
				|  |  | -    },
 | 
	
		
			
				|  |  | -    preload: {
 | 
	
		
			
				|  |  | -      type: String as PropType<'auto' | 'metadata' | 'none'>,
 | 
	
		
			
				|  |  | -      default: 'auto'
 | 
	
		
			
				|  |  | -    },
 | 
	
		
			
				|  |  | -    currentTime: {
 | 
	
		
			
				|  |  | +    isEmtry: {
 | 
	
		
			
				|  |  |        type: Boolean,
 | 
	
		
			
				|  |  | -      default: true
 | 
	
		
			
				|  |  | -    },
 | 
	
		
			
				|  |  | -    playsinline: {
 | 
	
		
			
				|  |  | -      type: Boolean,
 | 
	
		
			
				|  |  | -      default: true
 | 
	
		
			
				|  |  | -    },
 | 
	
		
			
				|  |  | -    onPlay: {
 | 
	
		
			
				|  |  | -      type: Function,
 | 
	
		
			
				|  |  | -      default: () => ({})
 | 
	
		
			
				|  |  | +      default: false
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |    },
 | 
	
		
			
				|  |  | -  emits: ['exitfullscreen'],
 | 
	
		
			
				|  |  | -  data() {
 | 
	
		
			
				|  |  | -    return {
 | 
	
		
			
				|  |  | -      player: null as any,
 | 
	
		
			
				|  |  | -      loading: true // 首次进入加载中
 | 
	
		
			
				|  |  | +  emits: ['loadedmetadata', 'togglePlay', 'ended', 'reset'],
 | 
	
		
			
				|  |  | +  setup(props, { emit, expose }) {
 | 
	
		
			
				|  |  | +    const { src, poster, isEmtry } = toRefs(props);
 | 
	
		
			
				|  |  | +    const videoRef = ref();
 | 
	
		
			
				|  |  | +    const videoItem = ref<Plyr>();
 | 
	
		
			
				|  |  | +    const controlID = 'v' + Date.now() + Math.floor(Math.random() * 100);
 | 
	
		
			
				|  |  | +    const playBtnId = 'play' + Date.now() + Math.floor(Math.random() * 100);
 | 
	
		
			
				|  |  | +    const replayBtnId = 'replay' + Date.now() + Math.floor(Math.random() * 100);
 | 
	
		
			
				|  |  | +    const toggleHideControl = (isShow: false) => {
 | 
	
		
			
				|  |  | +      videoItem.value?.toggleControls(isShow);
 | 
	
		
			
				|  |  | +    };
 | 
	
		
			
				|  |  | +    const togglePlay = (e: Event) => {
 | 
	
		
			
				|  |  | +      e.stopPropagation();
 | 
	
		
			
				|  |  | +      videoItem.value?.togglePlay();
 | 
	
		
			
				|  |  | +    };
 | 
	
		
			
				|  |  | +    const toggleReplay = () => {
 | 
	
		
			
				|  |  | +      const replayBtn = document.getElementById(replayBtnId);
 | 
	
		
			
				|  |  | +      if (!replayBtn || !videoItem.value) return;
 | 
	
		
			
				|  |  | +      videoItem.value.restart();
 | 
	
		
			
				|  |  | +    };
 | 
	
		
			
				|  |  | +    const onDefault = () => {
 | 
	
		
			
				|  |  | +      document
 | 
	
		
			
				|  |  | +        .getElementById(controlID)
 | 
	
		
			
				|  |  | +        ?.addEventListener('click', (e: Event) => {
 | 
	
		
			
				|  |  | +          e.stopPropagation();
 | 
	
		
			
				|  |  | +          emit('reset');
 | 
	
		
			
				|  |  | +        });
 | 
	
		
			
				|  |  | +      document.getElementById(playBtnId)?.addEventListener('click', togglePlay);
 | 
	
		
			
				|  |  | +      document
 | 
	
		
			
				|  |  | +        .getElementById(replayBtnId)
 | 
	
		
			
				|  |  | +        ?.addEventListener('click', toggleReplay);
 | 
	
		
			
				|  |  |      };
 | 
	
		
			
				|  |  | -  },
 | 
	
		
			
				|  |  | -  mounted() {
 | 
	
		
			
				|  |  | -    this._init();
 | 
	
		
			
				|  |  | -  },
 | 
	
		
			
				|  |  | -  methods: {
 | 
	
		
			
				|  |  | -    _init() {
 | 
	
		
			
				|  |  | -      // controls: [
 | 
	
		
			
				|  |  | -      //   'play-large' ,  // 中间的大播放按钮
 | 
	
		
			
				|  |  | -      //   'restart' ,  // 重新开始播放
 | 
	
		
			
				|  |  | -      //   'rewind' ,  // 按寻道时间倒带(默认 10 秒)
 | 
	
		
			
				|  |  | -      //   'play' ,  // 播放/暂停播放
 | 
	
		
			
				|  |  | -      //   'fast-forward' ,  // 快进查找时间(默认 10 秒)
 | 
	
		
			
				|  |  | -      //   'progress' ,  // 播放和缓冲的进度条和滑动条
 | 
	
		
			
				|  |  | -      //   'current-time' ,  // 播放的当前时间
 | 
	
		
			
				|  |  | -      //   ' duration' ,  // 媒体的完整持续时间
 | 
	
		
			
				|  |  | -      //   'mute' ,  // 切换静音
 | 
	
		
			
				|  |  | -      //   'volume', // 音量控制
 | 
	
		
			
				|  |  | -      //   'captions' ,  // 切换字幕
 | 
	
		
			
				|  |  | -      //   'settings' ,  // 设置菜单
 | 
	
		
			
				|  |  | -      //   'pip' ,  // 画中画(当前仅 Safari)
 | 
	
		
			
				|  |  | -      //   'airplay' ,  // Airplay(当前仅 Safari)
 | 
	
		
			
				|  |  | -      //   'download ' ,  // 显示一个下载按钮,其中包含指向当前源或您在选项中指定的自定义 URL 的链接
 | 
	
		
			
				|  |  | -      //   'fullscreen' ,  // 切换全屏
 | 
	
		
			
				|  |  | -      // ] ;
 | 
	
		
			
				|  |  | -      const controls = [
 | 
	
		
			
				|  |  | -        'play-large',
 | 
	
		
			
				|  |  | -        'play',
 | 
	
		
			
				|  |  | -        'progress',
 | 
	
		
			
				|  |  | -        'captions',
 | 
	
		
			
				|  |  | -        'fullscreen'
 | 
	
		
			
				|  |  | -      ];
 | 
	
		
			
				|  |  | -      if (this.currentTime) {
 | 
	
		
			
				|  |  | -        controls.push('current-time');
 | 
	
		
			
				|  |  | -      }
 | 
	
		
			
				|  |  | -      const params: any = {
 | 
	
		
			
				|  |  | -        controls: controls,
 | 
	
		
			
				|  |  | -        ...this.setting,
 | 
	
		
			
				|  |  | -        invertTime: false
 | 
	
		
			
				|  |  | -      };
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -      if (browser().iPhone) {
 | 
	
		
			
				|  |  | -        params.fullscreen = {
 | 
	
		
			
				|  |  | -          enabled: true,
 | 
	
		
			
				|  |  | -          fallback: 'force',
 | 
	
		
			
				|  |  | -          iosNative: true
 | 
	
		
			
				|  |  | -        };
 | 
	
		
			
				|  |  | +    const changePlayBtn = (code: string) => {
 | 
	
		
			
				|  |  | +      const playBtn = document.getElementById(playBtnId);
 | 
	
		
			
				|  |  | +      if (!playBtn) return;
 | 
	
		
			
				|  |  | +      if (code == 'play') {
 | 
	
		
			
				|  |  | +        playBtn.classList.remove(styles.btnPause);
 | 
	
		
			
				|  |  | +        playBtn.classList.add(styles.btnPlay);
 | 
	
		
			
				|  |  | +      } else {
 | 
	
		
			
				|  |  | +        playBtn.classList.remove(styles.btnPlay);
 | 
	
		
			
				|  |  | +        playBtn.classList.add(styles.btnPause);
 | 
	
		
			
				|  |  |        }
 | 
	
		
			
				|  |  | +    };
 | 
	
		
			
				|  |  | +    const controls = `
 | 
	
		
			
				|  |  | +            <div id="${controlID}" class="plyr__controls bottomFixed ${styles.controls}">
 | 
	
		
			
				|  |  | +                <div class="${styles.actions}">
 | 
	
		
			
				|  |  | +                    <div class="${styles.actionWrap}">
 | 
	
		
			
				|  |  | +                        <button id="${playBtnId}" class="${styles.actionBtn}">
 | 
	
		
			
				|  |  | +                            <div class="van-loading van-loading--circular" aria-live="polite" aria-busy="true"><span class="van-loading__spinner van-loading__spinner--circular" style="color: rgb(255, 255, 255);"><svg class="van-loading__circular" viewBox="25 25 50 50"><circle cx="50" cy="50" r="20" fill="none"></circle></svg></span></div>
 | 
	
		
			
				|  |  | +                            <img class="${styles.playIcon}" src="${iconplay}" />
 | 
	
		
			
				|  |  | +                            <img class="${styles.playIcon}" src="${iconpause}" />
 | 
	
		
			
				|  |  | +                        </button>
 | 
	
		
			
				|  |  | +                    </div>
 | 
	
		
			
				|  |  | +                    <div class="${styles.time}">
 | 
	
		
			
				|  |  | +                        <div class="plyr__time plyr__time--current" aria-label="Current time">00:00</div><span class="${styles.line}">/</span>
 | 
	
		
			
				|  |  | +                        <div class="plyr__time plyr__time--duration" aria-label="Duration">00:00</div>
 | 
	
		
			
				|  |  | +                    </div>
 | 
	
		
			
				|  |  | +                </div>
 | 
	
		
			
				|  |  | +                <div class="${styles.slider}">
 | 
	
		
			
				|  |  | +                    <div class="plyr__progress">
 | 
	
		
			
				|  |  | +                        <input data-plyr="seek" type="range" min="0" max="100" step="0.01" value="0" aria-label="Seek">
 | 
	
		
			
				|  |  | +                        <progress class="plyr__progress__buffer" min="0" max="100" value="0">% buffered</progress>
 | 
	
		
			
				|  |  | +                        <span role="tooltip" class="plyr__tooltip">00:00</span>
 | 
	
		
			
				|  |  | +                    </div>
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -      this.player = new Plyr((this as any).$refs.video, params);
 | 
	
		
			
				|  |  | +                </div>
 | 
	
		
			
				|  |  | +                <div class="${styles.actions}" style="padding-right: 0;">
 | 
	
		
			
				|  |  | +                    <button id="${replayBtnId}" class="${styles.actionBtn} ${styles.loopBtn}">
 | 
	
		
			
				|  |  | +                        <img class="loop" src="${iconReplay}" />
 | 
	
		
			
				|  |  | +                    </button>
 | 
	
		
			
				|  |  | +                </div>
 | 
	
		
			
				|  |  | +            </div>`;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -      this.player.on('play', () => {
 | 
	
		
			
				|  |  | -        this.onPlay && this.onPlay(this.player);
 | 
	
		
			
				|  |  | +    onMounted(() => {
 | 
	
		
			
				|  |  | +      videoItem.value = new Plyr(videoRef.value, {
 | 
	
		
			
				|  |  | +        autoplay: false,
 | 
	
		
			
				|  |  | +        controls: controls,
 | 
	
		
			
				|  |  | +        autopause: true, // 一次只允许
 | 
	
		
			
				|  |  | +        ratio: '16:9', // 强制所有视频的纵横比
 | 
	
		
			
				|  |  | +        // hideControls: false, // 在 2 秒没有鼠标或焦点移动、控制元素模糊(制表符退出)、播放开始或进入全屏时自动隐藏视频控件。只要移动鼠标、聚焦控制元素或暂停播放,控件就会立即重新出现。
 | 
	
		
			
				|  |  | +        clickToPlay: false, // 单击(或点击)视频容器将切换播放/暂停
 | 
	
		
			
				|  |  | +        fullscreen: { enabled: false, fallback: false, iosNative: false } // 不适用全屏
 | 
	
		
			
				|  |  |        });
 | 
	
		
			
				|  |  | +      if (videoItem.value) {
 | 
	
		
			
				|  |  | +        videoItem.value.on('play', () => {
 | 
	
		
			
				|  |  | +          if (videoItem.value) {
 | 
	
		
			
				|  |  | +            videoItem.value.muted = false;
 | 
	
		
			
				|  |  | +            videoItem.value.volume = 1;
 | 
	
		
			
				|  |  | +          }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -      this.player.on('enterfullscreen', () => {
 | 
	
		
			
				|  |  | -        console.log('fullscreen');
 | 
	
		
			
				|  |  | -        const i = document.createElement('i');
 | 
	
		
			
				|  |  | -        i.id = 'fullscreen-back';
 | 
	
		
			
				|  |  | -        i.className = 'van-icon van-icon-arrow-left video-back';
 | 
	
		
			
				|  |  | -        i.addEventListener('click', () => {
 | 
	
		
			
				|  |  | -          this.player.fullscreen.exit();
 | 
	
		
			
				|  |  | +          changePlayBtn('');
 | 
	
		
			
				|  |  | +        });
 | 
	
		
			
				|  |  | +        videoItem.value.on('pause', () => {
 | 
	
		
			
				|  |  | +          changePlayBtn('play');
 | 
	
		
			
				|  |  | +        });
 | 
	
		
			
				|  |  | +        videoItem.value.on('ended', () => {
 | 
	
		
			
				|  |  | +          emit('ended');
 | 
	
		
			
				|  |  | +          changePlayBtn('play');
 | 
	
		
			
				|  |  | +        });
 | 
	
		
			
				|  |  | +        videoItem.value.once('loadedmetadata', () => {
 | 
	
		
			
				|  |  | +          changePlayBtn('play');
 | 
	
		
			
				|  |  |          });
 | 
	
		
			
				|  |  | -        console.log(document.getElementsByClassName('plyr'));
 | 
	
		
			
				|  |  | -        document.getElementsByClassName('plyr')[0].appendChild(i);
 | 
	
		
			
				|  |  | -      });
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -      this.player.on('exitfullscreen', () => {
 | 
	
		
			
				|  |  | -        console.log('exitfullscreen');
 | 
	
		
			
				|  |  | -        const i = document.getElementById('fullscreen-back');
 | 
	
		
			
				|  |  | -        i && i.remove();
 | 
	
		
			
				|  |  | -        this.$emit('exitfullscreen');
 | 
	
		
			
				|  |  | -      });
 | 
	
		
			
				|  |  | -    },
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    onReplay() {
 | 
	
		
			
				|  |  | -      this.player.restart();
 | 
	
		
			
				|  |  | -      this.player.play();
 | 
	
		
			
				|  |  | -    },
 | 
	
		
			
				|  |  | -    onStop() {
 | 
	
		
			
				|  |  | -      this.player.stop();
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -  },
 | 
	
		
			
				|  |  | -  unmounted() {
 | 
	
		
			
				|  |  | -    this.player?.destroy();
 | 
	
		
			
				|  |  | -  },
 | 
	
		
			
				|  |  | -  render() {
 | 
	
		
			
				|  |  | -    return (
 | 
	
		
			
				|  |  | -      <div class={styles['video-container']}>
 | 
	
		
			
				|  |  | +        nextTick(() => {
 | 
	
		
			
				|  |  | +          onDefault();
 | 
	
		
			
				|  |  | +        });
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  | +    });
 | 
	
		
			
				|  |  | +    expose({
 | 
	
		
			
				|  |  | +      changePlayBtn,
 | 
	
		
			
				|  |  | +      toggleHideControl
 | 
	
		
			
				|  |  | +    });
 | 
	
		
			
				|  |  | +    return () => (
 | 
	
		
			
				|  |  | +      <div class={styles.videoWrap}>
 | 
	
		
			
				|  |  |          <video
 | 
	
		
			
				|  |  | -          ref="video"
 | 
	
		
			
				|  |  | -          class={styles['video']}
 | 
	
		
			
				|  |  | -          src={this.src}
 | 
	
		
			
				|  |  | -          playsinline={this.playsinline}
 | 
	
		
			
				|  |  | -          poster={this.poster}
 | 
	
		
			
				|  |  | -          preload={this.preload}
 | 
	
		
			
				|  |  | -          style={{ ...this.styleValue }}></video>
 | 
	
		
			
				|  |  | -        {/* </div> */}
 | 
	
		
			
				|  |  | +          style={{ width: '100%', height: '100%' }}
 | 
	
		
			
				|  |  | +          src={isEmtry.value ? '' : src.value}
 | 
	
		
			
				|  |  | +          poster={poster.value}
 | 
	
		
			
				|  |  | +          ref={videoRef}
 | 
	
		
			
				|  |  | +          playsinline="false"></video>
 | 
	
		
			
				|  |  |        </div>
 | 
	
		
			
				|  |  |      );
 | 
	
		
			
				|  |  |    }
 |