video-class.tsx 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. import { defineComponent, onMounted, ref, watch, Transition, toRefs, nextTick } from 'vue'
  2. import styles from './index.module.less'
  3. import { Slider } from 'vant'
  4. import iconplay from '../coursewarePlay/image/icon-play.svg'
  5. import iconpause from '../coursewarePlay/image/icon-pause.svg'
  6. import iconVideobg from '../coursewarePlay/image/icon-videobg.png'
  7. import { getSecondRPM } from '@/helpers/utils'
  8. import TCPlayer from 'tcplayer.js'
  9. import 'tcplayer.js/dist/tcplayer.min.css'
  10. export default defineComponent({
  11. name: 'video-class',
  12. props: {
  13. item: {
  14. type: Object,
  15. default: () => {
  16. return {}
  17. }
  18. },
  19. modal: {
  20. type: Boolean,
  21. default: true
  22. }
  23. },
  24. emits: ['loadedmetadata', 'togglePlay', 'ended', 'reset', 'error', 'close', 'changeModal'],
  25. setup(props, { emit }) {
  26. const { item, modal } = toRefs(props)
  27. const videoItem = ref()
  28. const videoID = 'video' + Date.now() + Math.floor(Math.random() * 100)
  29. const __init = () => {
  30. if (videoItem.value) {
  31. nextTick(() => {
  32. videoItem.value?.pause()
  33. })
  34. console.log(props.item, item.value)
  35. videoItem.value.poster(props.item.coverImg) // 封面
  36. videoItem.value.src(props.item.content) // url 播放地址
  37. videoItem.value.loop(props.item.loop)
  38. videoItem.value.muted(props.item.muted)
  39. videoItem.value.autoplay(props.item.autoplay)
  40. // 初步加载时
  41. videoItem.value.one('loadedmetadata', (e: any) => {
  42. if (item.value.autoplay && videoItem.value) {
  43. videoItem.value?.play()
  44. }
  45. // 获取时长
  46. const videoEle = videoItem.value
  47. item.value.duration = videoEle.duration()
  48. item.value.videoEle = videoEle
  49. item.value.loaded = true
  50. emit('loadedmetadata', videoItem.value)
  51. })
  52. // 视频播放时加载
  53. videoItem.value.on('timeupdate', () => {
  54. if (!item.value.loaded) return
  55. const videoEle = videoItem.value
  56. item.value.currentTime = videoEle.currentTime()
  57. })
  58. // 视频播放结束
  59. videoItem.value.on('ended', () => {
  60. emit('ended', item.value)
  61. })
  62. //
  63. videoItem.value.on('pause', () => {
  64. console.log('暂停')
  65. //暂停
  66. item.value.paused = true
  67. item.value.videoEle?.pause()
  68. })
  69. videoItem.value.on('play', () => {
  70. item.value.paused = false
  71. // 播放
  72. if (item.value.muted) {
  73. item.value.muted = false
  74. item.value.videoEle?.muted(false)
  75. item.value.videoEle?.volume(1)
  76. item.value.videoEle?.pause()
  77. }
  78. })
  79. // 视频播放异常
  80. videoItem.value.on('error', () => {
  81. emit('error')
  82. })
  83. }
  84. }
  85. onMounted(() => {
  86. videoItem.value = TCPlayer(videoID, {
  87. appID: '',
  88. controls: false,
  89. loop: item.value.loop,
  90. muted: item.value.muted
  91. // autoplay: true
  92. }) // player-container-id 为播放器容器 ID,必须与 html 中一致
  93. __init()
  94. })
  95. watch(
  96. () => props.item,
  97. () => {
  98. __init()
  99. }
  100. )
  101. return () => (
  102. <>
  103. <div
  104. class={styles.itemDiv}
  105. onClick={() => {
  106. clearTimeout(item.value.timer)
  107. // activeData.model = !activeData.model
  108. emit('changeModal', !modal.value)
  109. }}
  110. >
  111. <video
  112. id={videoID}
  113. style={{ height: '100%', width: '100%' }}
  114. playsinline="false"
  115. preload="auto"
  116. class="player"
  117. poster={iconVideobg}
  118. data-vid={item.value.id}
  119. src={item.value.content}
  120. loop={item.value.loop}
  121. autoplay={item.value.autoplay}
  122. muted={item.value.muted}
  123. >
  124. <source src={item.value.content} type="video/mp4" />
  125. </video>
  126. <div class={styles.videoSection}></div>
  127. </div>
  128. <Transition name="bottom">
  129. {modal.value && !item.value.muted && (
  130. <div class={styles.bottomFixedContainer}>
  131. <div class={styles.time}>
  132. <span>{getSecondRPM(item.value.currentTime)}</span>
  133. <span>{getSecondRPM(item.value.duration)}</span>
  134. </div>
  135. <div class={styles.slider}>
  136. {item.value.duration && (
  137. <Slider
  138. buttonSize={16}
  139. modelValue={item.value.currentTime}
  140. min={0}
  141. max={item.value.duration}
  142. />
  143. )}
  144. </div>
  145. <div class={styles.actions}>
  146. <div class={styles.actionBtn}>
  147. {item.value.paused ? (
  148. <img
  149. src={iconplay}
  150. onClick={() => {
  151. clearTimeout(item.value.timer)
  152. item.value.videoEle?.play()
  153. item.value.paused = false
  154. item.value.timer = setTimeout(() => {
  155. // activeData.model = false
  156. emit('changeModal', false)
  157. }, 4000)
  158. }}
  159. />
  160. ) : (
  161. <img
  162. src={iconpause}
  163. onClick={() => {
  164. clearTimeout(item.value.timer)
  165. item.value.videoEle?.pause()
  166. item.value.paused = true
  167. }}
  168. />
  169. )}
  170. </div>
  171. </div>
  172. </div>
  173. )}
  174. </Transition>
  175. </>
  176. )
  177. }
  178. })