| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156 |
- /*
- * Tencent is pleased to support the open source community by making vap available.
- *
- * Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
- *
- * Licensed under the MIT License (the "License"); you may not use this file except in
- * compliance with the License. You may obtain a copy of the License at
- *
- * http://opensource.org/licenses/MIT
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License is
- * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
- * either express or implied. See the License for the specific language governing permissions and
- * limitations under the License.
- */
- export default class VapVideo {
- constructor(options) {
- if (!options.container || !options.src) {
- return console.warn('[Alpha video]: options container and src cannot be empty!')
- }
- this.options = Object.assign(
- {
- // 视频url
- src: '',
- // 循环播放
- loop: false,
- fps: 20,
- // 视频宽度
- width: 375,
- // 视频高度
- height: 375,
- // 容器
- container: null,
- config: ''
- },
- options
- )
- this.fps = 20
- this.requestAnim = this.requestAnimFunc(this.fps)
- this.container = this.options.container
- if (!this.options.src || !this.options.config || !this.options.container) {
- console.error('参数出错:src(视频地址)、config(配置文件地址)、container(dom容器)')
- } else {
- // 创建video
- this.initVideo()
- }
- }
- initVideo() {
- const options = this.options
- // 创建video
- const video = (this.video = document.createElement('video'))
- video.crossOrigin = 'anonymous'
- video.autoplay = false
- // video.muted = true
- // video.volume = 0
- video.style.display = 'none'
- video.src = options.src
- video.loop = !!options.loop
- // 这里要插在body上,避免container移动带来无法播放的问题
- document.body.appendChild(this.video)
- // 绑定事件
- this.events = {}
- ;['playing', 'pause', 'ended', 'error'].forEach(item => {
- this.on(item, this['on' + item].bind(this))
- })
- video.load()
- }
- drawFrame() {
- this._drawFrame = this._drawFrame || this.drawFrame.bind(this)
- this.animId = this.requestAnim(this._drawFrame)
- }
- play() {
- const prom = this.video && this.video.play()
- if (prom && prom.then) {
- prom.catch(e => {
- if (!this.video) {
- return
- }
- this.video.muted = true
- this.video.volume = 0
- this.video.play().catch(e => {
- ;(this.events.error || []).forEach(item => {
- item(e)
- })
- })
- })
- }
- }
- requestAnimFunc() {
- const me = this
- if (window.requestAnimationFrame) {
- let index = -1
- return function(cb) {
- index++
- return requestAnimationFrame(() => {
- if (!(index % (60 / me.fps))) {
- return cb()
- }
- me.animId = me.requestAnim(cb)
- })
- }
- }
- return function(cb) {
- return setTimeout(cb, 1000 / me.fps)
- }
- }
- cancelRequestAnimation() {
- if (window.cancelAnimationFrame) {
- cancelAnimationFrame(this.animId)
- }
- clearTimeout(this.animId)
- }
- destroy() {
- if (this.video) {
- this.video.parentNode && this.video.parentNode.removeChild(this.video)
- this.video = null
- }
- this.cancelRequestAnimation(this.animId)
- }
- clear() {
- this.destroy()
- }
- on(event, callback) {
- const cbs = this.events[event] || []
- cbs.push(callback)
- this.events[event] = cbs
- this.video.addEventListener(event, callback)
- return this
- }
- onplaying() {
- if (!this.firstPlaying) {
- this.firstPlaying = true
- this.drawFrame()
- }
- }
- onpause() {}
- onended() {
- this.destroy()
- }
- onerror(err) {
- console.error('[Alpha video]: play error: ', err)
- this.destroy()
- }
- }
|