UNPKG

tcplayer-plugin

Version:

基于腾讯云播放器的组件库,支持Vue2、Vue3和原生JS

486 lines (449 loc) 13.6 kB
/*! * tcplayer-plugin v0.1.0 * (c) 2025 * Released under the MIT License. */ 'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); var vue = require('vue'); // 动态加载资源(JS和CSS) function loadResource(sources, cb) { let arr = [...sources]; if (!arr.length) { cb && cb(); console.log('resouce loaded'); return false; } let item = arr.shift(); if (!item) { loadResource(arr, cb); return false; } if (item.endsWith('.js')) { getJS(item, () => { loadResource(arr, cb); }); } else if (item.endsWith('.css')) { getCss(item, () => { loadResource(arr, cb); }); } else { console.warn('no suport resource:', item); loadResource(arr, cb); } } // 动态加载JS文件 function getJS(url, callback) { if (document.querySelector(`script[src="${url}"]`)) { console.log(url, ':已存在'); callback && callback(); return false; } var script = document.createElement('script'), fn = callback || function () {}; script.type = 'text/javascript'; //IE if (script.readyState) { script.onreadystatechange = function () { if (script.readyState == 'loaded' || script.readyState == 'complete') { script.onreadystatechange = null; fn(); } else { script.onreadystatechange = null; fn(); } }; } else { //其他浏览器 script.onload = function () { fn(); }; script.onerror = function (err) { fn(); console.log(err); }; } script.src = url; document.querySelector('body').appendChild(script); } // 动态加载CSS文件 function getCss(url, callback) { if (document.querySelector(`link[href="${url}"]`)) { console.log(url, ':已存在'); callback && callback(); return false; } var css = document.createElement('link'), fn = callback || function () {}; css.rel = 'stylesheet'; //IE if (css.readyState) { css.onreadystatechange = function () { if (css.readyState == 'loaded' || css.readyState == 'complete') { css.onreadystatechange = null; fn(); } else { css.onreadystatechange = null; fn(); } }; } else { //其他浏览器 css.onload = function () { fn(); }; css.onerror = function (err) { fn(); console.log(err); }; } css.href = url; document.querySelector('head').appendChild(css); } // 全局变量 if (typeof window !== 'undefined') { window._pursuer = window._pursuer || {}; } var script = { name: 'TcPlayer', // 组件名称,确保与import时一致 props: { config: { type: Object, default() { return {}; } } }, data() { return { id: '', duration: 0, currentTime: 0, hearttime: 20000, // 心跳时间 timers: [], initShow: true, _source_loded: false }; }, watch: { 'config': { handler(val) { if (val && this._source_loded) ; }, deep: true } }, mounted() { if (typeof window === 'undefined') { return false; } this.id = this.getCfPlayerId(); const resources = []; const tcplayer = '//web.sdk.qcloud.com/player/tcplayer/release/v4.5.2/tcplayer.v4.5.2.min.js'; const tcplayerCss = '//web.sdk.qcloud.com/player/tcplayer/release/v4.5.2/tcplayer.min.css'; const hls = '//web.sdk.qcloud.com/player/tcplayer/release/v4.5.2/libs/hls.min.0.13.2m.js'; if (!window.TCPlayer) { resources.push(tcplayerCss, hls, tcplayer); } loadResource(resources, () => { this._source_loded = true; this.$nextTick(() => { this.init(); }); }); this.$playerBox = document; this.$playerBox.addEventListener('keydown', this.onkeydown, true); this.$playerBox.addEventListener('keyup', this.onkeyup, true); }, // Vue 2生命周期 beforeDestroy() { this.destroy(); }, // Vue 3生命周期 beforeUnmount() { this.destroy(); }, methods: { getCfPlayerId() { const $pursuer = typeof window !== 'undefined' ? window._pursuer : {}; $pursuer.playerCount = $pursuer.playerCount ? $pursuer.playerCount + 1 : 1; const id = this.config && this.config.id || 'player-container-id'; return id; }, init() { if (!document.querySelector(`#${this.id}`)) { return console.log(`#${this.id} dom is not found`); } const playerConfig = { width: '686px', height: '450px', reportable: true, }; this.initPlayer({ ...playerConfig, ...(this.config.tconfig || {}) }); }, initPlayer(config) { if (this.$player) { this.destroy(); console.log('run tcplayer destroy'); } if (!window.TCPlayer) { console.log('TCPlayer not found in window'); return false; } this.hearttime = this.config.hearttime || this.hearttime; console.log('init player config:', config); this.runs(config); }, runs(config) { this.$player = new window.TCPlayer(this.id, config); this.$player.on('ready', this.onready); this.$player.on('error', this.onerror); this.$player.on('timeupdate', this.ontimeupdate); this.$player.on('pause', this.onpause); this.$player.on('play', this.onplay); this.$player.on('ended', this.onended); this.$player.on('waiting', this.onwaiting); this.$player.on('snapshoted', this.onsnapshoted); this.$player.on('sourceloaded', this.onsourceloaded); // API兼容处理 this.$player.getDuration = this.$player.duration; this.$player.getCurrentTime = this.$player.currentTime; this.$player._el = this.$player.el_; this.$player.seek = this.$player.currentTime; this.$player.getStatus = this.$player.getStatus || function() { return this.$player.paused() ? 'pause' : 'playing'; }.bind(this); this.$player.destroy = this.$player.dispose; this.$player._originalPlaybackRate = this.$player.playbackRate; this.$player.getVolume = this.$player.volume; this.$player.setVolume = this.$player.volume; }, onsourceloaded(params) { const paramData = params.paramData; const desc = paramData.desc; const definition = paramData.definition; // 获取清晰度组件并调用清晰度组件的 setCurrentQuality 设置清晰度 try { const qualityComponent = this.$player.getComponent('QualityComponent'); if (qualityComponent && typeof qualityComponent.setCurrentQuality === 'function') { qualityComponent.setCurrentQuality(desc, definition); } } catch(e) { console.warn('设置清晰度失败:', e); } }, onready() { console.log('onready:', this.$player); // 开始执行心跳 this.onheart(true); this.$emit('onready', this.$player); this.config.onready && this.config.onready(this.$player); }, onerror(err) { console.log('error:', err); this.$emit('onerror', this.$player); this.config.onerror && this.config.onerror(this.$player); }, ontimeupdate() { this.onheart(); this.duration = this.$player.getDuration(); this.currentTime = this.$player.getCurrentTime(); this.$emit('ontimeupdate', this.duration, this.currentTime, this.$player); this.config.ontimeupdate && this.config.ontimeupdate(this.duration, this.currentTime, this.$player); }, onpause() { console.log('onpause:', this.$player); this.$emit('onpause', this.$player); this.config.onpause && this.config.onpause(this.$player); }, onplay() { console.log('onplay:'); this.$emit('onplay', this.$player); this.config.onplay && this.config.onplay(this.$player); }, onended() { console.log('ended'); // 结束执行心跳 this.onheart(true); this.$emit('onended', this.$player); this.config.onended && this.config.onended(this.$player); }, onnext() { this.$emit('onnext', this.$player); this.config.onnext && this.config.onnext(this.$player); }, onpre() { this.$emit('onpre', this.$player); this.config.onpre && this.config.onpre(this.$player); }, onwaiting() { this.$emit('onwaiting', this.$player); this.config.onwaiting && this.config.onwaiting(this.$player); }, // 截图 onsnapshoted(data) { this.$emit('onsnapshoted', data, this.$player); this.config.onsnapshoted && this.config.onsnapshoted(data, this.$player); }, // 心跳 onheart(novalite) { if (novalite) { this.$emit('onheart', this.$player); this.config.onheart && this.config.onheart(this.$player); return false; } if (this.onheart_lock) { return false; } clearTimeout(this.timers[0]); this.timers[0] = null; this.onheart_lock = true; this.timers[0] = setTimeout(() => { this.onheart_lock = false; this.$emit('onheart', this.$player); this.config.onheart && this.config.onheart(this.$player); }, this.hearttime); }, destroy() { if (this.$player) { clearTimeout(this.timers[0] || null); this.onheart_lock = false; this.$player.off('ready', this.onready); this.$player.off('error', this.onerror); this.$player.off('timeupdate', this.ontimeupdate); this.$player.off('pause', this.onpause); this.$player.off('play', this.onplay); this.$player.off('ended', this.onended); this.$player.off('waiting', this.onwaiting); this.$player.off('snapshoted', this.onsnapshoted); this.$player.off('sourceloaded', this.onsourceloaded); try { this.$player.destroy(); } catch (e) { console.log('destroy error:', e); } this.$player = null; } if (this.$playerBox) { this.$playerBox.removeEventListener('keydown', this.onkeydown, true); this.$playerBox.removeEventListener('keyup', this.onkeyup, true); this.$playerBox = null; } } } }; const _hoisted_1 = { class: "ps-player" }; const _hoisted_2 = ["id"]; function render(_ctx, _cache, $props, $setup, $data, $options) { return (vue.openBlock(), vue.createElementBlock("div", _hoisted_1, [ ($data.initShow) ? (vue.openBlock(), vue.createElementBlock("video", { key: 0, id: "player-container-id", preload: "auto", playsinline: "", "webkit-playsinline": "", tabindex: "1", ref: "playerBox", class: "ps-player-container" }, null, 8 /* PROPS */, _hoisted_2)) : vue.createCommentVNode("v-if", true) ])) } script.render = render; script.__file = "src/tcplayer.vue"; // 项目版本号,与package.json保持一致 const version = '0.1.0'; // 检测Vue版本 const isVue2 = vue => vue && !!vue.prototype; const isVue3 = vue => vue && !!vue.config && !!vue.config.globalProperties; // Vue2和Vue3兼容安装函数 const install = function install(app, options = {}) { if (isVue2(app)) { // Vue 2安装方式 app.component(script.name, script); } else if (isVue3(app)) { // Vue 3安装方式 app.component(script.name, script); } else { console.error('[TcPlayer] 不支持的Vue版本,请使用Vue 2.x或3.x'); } }; // 为Vue2创建一个具有install方法的对象 script.install = install; // 自动安装(当通过script标签引入时) if (typeof window !== 'undefined' && window.Vue) { if (isVue2(window.Vue)) { window.Vue.use(script); } else if (isVue3(window.Vue)) { window.Vue.use({ install }); } } // 原生JS用法 class TcPlayerJS { constructor(element, options) { if (typeof element === 'string') { element = document.querySelector(element); } if (!element) { throw new Error('[TcPlayer] 目标DOM元素不存在'); } this.element = element; this.options = options || {}; this._init(); } _init() { // 将Vue组件渲染到目标元素 const container = document.createElement('div'); container.className = 'tc-player-container'; this.element.appendChild(container); // 这里使用运行时API创建组件实例 if (window.Vue) { if (isVue3(window.Vue)) { const app = window.Vue.createApp({ render: () => window.Vue.h(script, { props: this.options }) }); this.instance = app.mount(container); } else if (isVue2(window.Vue)) { const VueConstructor = window.Vue; const Component = VueConstructor.extend({ render: h => h(script, { props: this.options }) }); this.instance = new Component().$mount(container); } } else { console.error('[TcPlayer] 请先引入Vue.js'); } } destroy() { if (this.instance && this.instance.$destroy) { this.instance.$destroy(); } if (this.element) { this.element.innerHTML = ''; } } } // 默认导出一个具有Vue插件格式的对象 const plugin = { install, version, TcPlayer: script, TcPlayerJS }; // 确保为Vue2提供一个可用的install方法 plugin.install = install; exports.TcPlayer = script; exports.TcPlayerJS = TcPlayerJS; exports.default = plugin; exports.install = install; exports.version = version;