player.vue 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. <template>
  2. <div class="video-player" v-if="reseted">
  3. <video
  4. class="video-js vjs-fluid"
  5. ref="video"
  6. width="100%"
  7. height="100%"
  8. style="object-fit: fill!important;"
  9. ></video>
  10. </div>
  11. </template>
  12. <script>
  13. // lib
  14. import _videojs from 'video.js'
  15. const videojs = window.videojs || _videojs
  16. import "videojs-flash"
  17. // pollfill
  18. if (typeof Object.assign != 'function') {
  19. Object.defineProperty(Object, 'assign', {
  20. value(target, varArgs) {
  21. if (target == null) {
  22. throw new TypeError('Cannot convert undefined or null to object')
  23. }
  24. const to = Object(target)
  25. for (let index = 1; index < arguments.length; index++) {
  26. const nextSource = arguments[index]
  27. if (nextSource != null) {
  28. for (const nextKey in nextSource) {
  29. if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) {
  30. to[nextKey] = nextSource[nextKey]
  31. }
  32. }
  33. }
  34. }
  35. return to
  36. },
  37. writable: true,
  38. configurable: true
  39. })
  40. }
  41. // as of videojs 6.6.0
  42. const DEFAULT_EVENTS = [
  43. 'loadeddata',
  44. 'canplay',
  45. 'canplaythrough',
  46. 'play',
  47. 'pause',
  48. 'waiting',
  49. 'playing',
  50. 'ended',
  51. 'error'
  52. ]
  53. // export
  54. export default {
  55. name: 'video-player',
  56. props: {
  57. start: {
  58. type: Number,
  59. default: 0
  60. },
  61. crossOrigin: {
  62. type: String,
  63. default: ''
  64. },
  65. playsinline: {
  66. type: Boolean,
  67. default: false
  68. },
  69. customEventName: {
  70. type: String,
  71. default: 'statechanged'
  72. },
  73. options: {
  74. type: Object,
  75. required: true
  76. },
  77. events: {
  78. type: Array,
  79. default: () => []
  80. },
  81. globalOptions: {
  82. type: Object,
  83. default: () => ({
  84. // autoplay: false,
  85. controls: true,
  86. // preload: 'auto',
  87. // fluid: false,
  88. // muted: false,
  89. controlBar: {
  90. remainingTimeDisplay: false,
  91. playToggle: {},
  92. progressControl: {},
  93. fullscreenToggle: {},
  94. volumeMenuButton: {
  95. inline: false,
  96. vertical: true
  97. }
  98. },
  99. techOrder: ['html5'],
  100. plugins: {}
  101. })
  102. },
  103. globalEvents: {
  104. type: Array,
  105. default: () => []
  106. }
  107. },
  108. data() {
  109. return {
  110. player: null,
  111. reseted: true
  112. }
  113. },
  114. mounted() {
  115. if (!this.player) {
  116. this.initialize()
  117. }
  118. },
  119. beforeDestroy() {
  120. // if (this.player.techName_ !== 'Flash' && this.player.pause) { this.player.pause() }
  121. const videoDom = this.$refs.video
  122. videojs(videoDom).dispose()
  123. if (this.player) {
  124. this.dispose()
  125. }
  126. },
  127. methods: {
  128. initialize() {
  129. // videojs options
  130. const videoOptions = Object.assign({}, this.globalOptions, this.options)
  131. // ios fullscreen
  132. if (this.playsinline) {
  133. this.$refs.video.setAttribute('playsinline', this.playsinline)
  134. this.$refs.video.setAttribute('webkit-playsinline', this.playsinline)
  135. this.$refs.video.setAttribute('x5-playsinline', this.playsinline)
  136. this.$refs.video.setAttribute('x5-video-player-type', 'h5')
  137. this.$refs.video.setAttribute('x5-video-player-fullscreen', false)
  138. }
  139. // cross origin
  140. if (this.crossOrigin !== '') {
  141. this.$refs.video.crossOrigin = this.crossOrigin
  142. this.$refs.video.setAttribute('crossOrigin', this.crossOrigin)
  143. }
  144. // emit event
  145. const emitPlayerState = (event, value) => {
  146. if (event) {
  147. this.$emit(event, this.player)
  148. }
  149. if (value) {
  150. this.$emit(this.customEventName, { [event]: value })
  151. }
  152. }
  153. // avoid error "VIDEOJS: ERROR: Unable to find plugin: __ob__"
  154. if (videoOptions.plugins) {
  155. delete videoOptions.plugins.__ob__
  156. }
  157. // videoOptions
  158. // console.log('videoOptions', videoOptions)
  159. // player
  160. const self = this
  161. this.player = videojs(this.$refs.video, videoOptions, function() {
  162. // events
  163. const events = DEFAULT_EVENTS.concat(self.events).concat(self.globalEvents)
  164. // watch events
  165. const onEdEvents = {}
  166. for (let i = 0; i < events.length; i++) {
  167. if (typeof events[i] === 'string' && onEdEvents[events[i]] === undefined) {
  168. (event => {
  169. onEdEvents[event] = null
  170. this.on(event, () => {
  171. emitPlayerState(event, true)
  172. })
  173. })(events[i])
  174. }
  175. }
  176. // watch timeupdate
  177. this.on('timeupdate', function() {
  178. emitPlayerState('timeupdate', this.currentTime())
  179. })
  180. // player readied
  181. self.$emit('ready', this)
  182. })
  183. },
  184. dispose(callback) {
  185. if (this.player && this.player.dispose) {
  186. if (this.player.techName_ !== 'Flash') {
  187. this.player.pause && this.player.pause()
  188. }
  189. this.player.dispose()
  190. this.player = null
  191. this.$nextTick(() => {
  192. this.reseted = false
  193. this.$nextTick(() => {
  194. this.reseted = true
  195. this.$nextTick(() => {
  196. callback && callback()
  197. })
  198. })
  199. })
  200. /*
  201. if (!this.$el.children.length) {
  202. const video = document.createElement('video')
  203. video.className = 'video-js'
  204. this.$el.appendChild(video)
  205. }
  206. */
  207. }
  208. }
  209. },
  210. watch: {
  211. options: {
  212. deep: true,
  213. handler(options, oldOptions) {
  214. this.dispose(() => {
  215. if (options && options.sources && options.sources.length) {
  216. this.initialize()
  217. }
  218. })
  219. }
  220. }
  221. }
  222. }
  223. </script>