123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187 |
- import { defineComponent, nextTick, onMounted, onUnmounted, toRefs, watch } from 'vue'
- import 'plyr/dist/plyr.css'
- import Plyr from 'plyr'
- import { ref } from 'vue'
- import styles from './video.module.less'
- import iconLoop from '../image/icon-loop.svg'
- import iconLoopActive from '../image/icon-loop-active.svg'
- import iconplay from '../image/icon-play.svg'
- import iconpause from '../image/icon-pause.svg'
- export default defineComponent({
- name: 'video-play',
- props: {
- item: {
- type: Object,
- default: () => {
- return {}
- }
- },
- isEmtry: {
- type: Boolean,
- default: false
- },
- isActive: {
- type: Boolean,
- default: false
- }
- },
- emits: ['loadedmetadata', 'togglePlay', 'ended', 'reset'],
- setup(props, { emit, expose }) {
- const { item, isEmtry } = toRefs(props)
- const videoRef = ref()
- const videoItem: any = ref()
- const controlID = 'v' + Date.now() + Math.floor(Math.random() * 100)
- const playBtnId = 'play' + Date.now() + Math.floor(Math.random() * 100)
- const loopBtnId = 'loop' + 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 toggleLoop = (e: Event) => {
- const loopBtn = document.getElementById(loopBtnId)
- if (!loopBtn || !videoItem.value) return
- const isLoop = videoItem.value.loop
- if (isLoop) {
- loopBtn.classList.remove(styles.active)
- } else {
- loopBtn.classList.add(styles.active)
- }
- videoItem.value.loop = !videoItem.value.loop
- }
- const onDefault = () => {
- document.getElementById(controlID)?.addEventListener('click', (e: Event) => {
- e.stopPropagation()
- emit('reset')
- })
- document.getElementById(playBtnId)?.addEventListener('click', togglePlay)
- document.getElementById(loopBtnId)?.addEventListener('click', toggleLoop)
- }
- 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.time}">
- <div class="plyr__time plyr__time--current" aria-label="Current time">00:00</div>
- <div class="plyr__time plyr__time--duration" aria-label="Duration">00:00</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>
- </div>
- <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>
- <button id="${loopBtnId}" class="${styles.actionBtn} ${styles.loopBtn}">
- <img class="loop" src="${iconLoop}" />
- <img class="loopActive" src="${iconLoopActive}" />
- </button>
- </div>
- <div>${item.value.name}</div>
- </div>
- </div>`
- onMounted(() => {
- videoItem.value = new Plyr(videoRef.value, {
- autoplay: true,
- 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
- }
- // console.log('开始播放', item.value)
- if (!item.value.autoPlay && !item.value.isprepare && videoItem.value) {
- // 加载完成后,取消静音播放
- videoItem.value.pause()
- console.log(videoItem.value?.paused, 'video status')
- }
- changePlayBtn('')
- emit('togglePlay', videoItem.value?.paused)
- })
- videoItem.value.on('pause', () => {
- changePlayBtn('play')
- emit('togglePlay', videoItem.value?.paused)
- })
- videoItem.value.on('ended', (e: Event) => {
- emit('ended')
- changePlayBtn('play')
- })
- videoItem.value.once('loadedmetadata', (e: Event) => {
- changePlayBtn('play')
- videoItem.value.currentTime = 0
- if (item.value.autoPlay && videoItem.value) {
- videoItem.value.play()
- }
- emit('loadedmetadata', videoItem.value)
- })
- videoItem.value.on('timeupdate', (e: Event) => {
- // console.log(videoItem.value?.currentTime, '111')
- })
- nextTick(() => {
- onDefault()
- })
- }
- })
- expose({
- changePlayBtn,
- toggleHideControl
- })
- watch(
- () => props.isActive,
- (val) => {
- if (!val) {
- console.log(props.isActive, 'isActive')
- videoItem.value?.pause()
- }
- }
- )
- // onUnmounted(() => {
- // if (videoItem.value) {
- // videoItem.value?.pause()
- // videoItem.value?.destroy()
- // }
- // })
- return () => (
- <div class={styles.videoWrap}>
- <video
- style={{ width: '100%', height: '100%' }}
- src={isEmtry.value ? '' : item.value.content}
- ref={videoRef}
- playsinline="false"
- ></video>
- </div>
- )
- }
- })
|