video.js 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. /*
  2. * Tencent is pleased to support the open source community by making vap available.
  3. *
  4. * Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
  5. *
  6. * Licensed under the MIT License (the "License"); you may not use this file except in
  7. * compliance with the License. You may obtain a copy of the License at
  8. *
  9. * http://opensource.org/licenses/MIT
  10. *
  11. * Unless required by applicable law or agreed to in writing, software distributed under the License is
  12. * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
  13. * either express or implied. See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. export default class VapVideo {
  17. constructor(options) {
  18. if (!options.container || !options.src) {
  19. return console.warn('[Alpha video]: options container and src cannot be empty!')
  20. }
  21. this.options = Object.assign(
  22. {
  23. // 视频url
  24. src: '',
  25. // 循环播放
  26. loop: false,
  27. fps: 20,
  28. // 视频宽度
  29. width: 375,
  30. // 视频高度
  31. height: 375,
  32. // 容器
  33. container: null,
  34. config: ''
  35. },
  36. options
  37. )
  38. this.fps = 20
  39. this.requestAnim = this.requestAnimFunc(this.fps)
  40. this.container = this.options.container
  41. if (!this.options.src || !this.options.config || !this.options.container) {
  42. console.error('参数出错:src(视频地址)、config(配置文件地址)、container(dom容器)')
  43. } else {
  44. // 创建video
  45. this.initVideo()
  46. }
  47. }
  48. initVideo() {
  49. const options = this.options
  50. // 创建video
  51. const video = (this.video = document.createElement('video'))
  52. video.crossOrigin = 'anonymous'
  53. video.autoplay = false
  54. video.preload = 'auto'
  55. video.autoload = true
  56. // video.muted = true
  57. // video.volume = 0
  58. video.style.display = 'none'
  59. video.src = options.src
  60. video.loop = !!options.loop
  61. // 这里要插在body上,避免container移动带来无法播放的问题
  62. document.body.appendChild(this.video)
  63. // 绑定事件
  64. this.events = {}
  65. ;['playing', 'pause', 'ended', 'error'].forEach(item => {
  66. this.on(item, this['on' + item].bind(this))
  67. })
  68. video.load()
  69. }
  70. drawFrame() {
  71. this._drawFrame = this._drawFrame || this.drawFrame.bind(this)
  72. this.animId = this.requestAnim(this._drawFrame)
  73. }
  74. play() {
  75. const prom = this.video && this.video.play()
  76. if (prom && prom.then) {
  77. prom.catch(e => {
  78. if (!this.video) {
  79. return
  80. }
  81. this.video.muted = true
  82. this.video.volume = 0
  83. this.video.play().catch(e => {
  84. ;(this.events.error || []).forEach(item => {
  85. item(e)
  86. })
  87. })
  88. })
  89. }
  90. }
  91. requestAnimFunc() {
  92. const me = this
  93. if (window.requestAnimationFrame) {
  94. let index = -1
  95. return function(cb) {
  96. index++
  97. return requestAnimationFrame(() => {
  98. if (!(index % (60 / me.fps))) {
  99. return cb()
  100. }
  101. me.animId = me.requestAnim(cb)
  102. })
  103. }
  104. }
  105. return function(cb) {
  106. return setTimeout(cb, 1000 / me.fps)
  107. }
  108. }
  109. cancelRequestAnimation() {
  110. if (window.cancelAnimationFrame) {
  111. cancelAnimationFrame(this.animId)
  112. }
  113. clearTimeout(this.animId)
  114. }
  115. destroy() {
  116. if (this.video) {
  117. this.video.parentNode && this.video.parentNode.removeChild(this.video)
  118. this.video = null
  119. }
  120. this.cancelRequestAnimation(this.animId)
  121. }
  122. clear() {
  123. this.destroy()
  124. }
  125. on(event, callback) {
  126. const cbs = this.events[event] || []
  127. cbs.push(callback)
  128. this.events[event] = cbs
  129. this.video.addEventListener(event, callback)
  130. return this
  131. }
  132. onplaying() {
  133. if (!this.firstPlaying) {
  134. this.firstPlaying = true
  135. this.drawFrame()
  136. }
  137. }
  138. onpause() {}
  139. onended() {
  140. this.destroy()
  141. }
  142. onerror(err) {
  143. console.error('[Alpha video]: play error: ', err)
  144. this.destroy()
  145. }
  146. }