FeaturedCommentXgPlayer.vue 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249
  1. <template>
  2. <view class="fc-xg-player-host rating-msg-video">
  3. <!-- #ifdef MP-WEIXIN -->
  4. <video
  5. :id="playerId"
  6. class="fc-xg-player-mp-video"
  7. :src="videoUrl"
  8. :poster="poster"
  9. :controls="false"
  10. object-fit="fill"
  11. :show-play-btn="false"
  12. :show-center-play-btn="false"
  13. :enable-progress-gesture="false"
  14. ></video>
  15. <!-- #endif -->
  16. <!-- #ifndef MP-WEIXIN -->
  17. <view
  18. class="fc-xg-player-render"
  19. :fcXgPlayerConfig="fcXgPlayerConfig"
  20. :change:fcXgPlayerConfig="fcXgRender.onConfig"
  21. :fcXgPauseCmd="fcXgPauseCmd"
  22. :change:fcXgPauseCmd="fcXgRender.onPause"
  23. >
  24. <view :id="playerId" class="fc-xg-player-inner"></view>
  25. </view>
  26. <!-- #endif -->
  27. </view>
  28. </template>
  29. <script>
  30. export default {
  31. name: 'FeaturedCommentXgPlayer',
  32. props: {
  33. playerId: {
  34. type: String,
  35. required: true
  36. },
  37. videoUrl: {
  38. type: String,
  39. default: ''
  40. },
  41. poster: {
  42. type: String,
  43. default: ''
  44. }
  45. },
  46. data() {
  47. return {
  48. fcXgPauseCmd: 0
  49. }
  50. },
  51. computed: {
  52. fcXgPlayerConfig() {
  53. return {
  54. playerId: this.playerId,
  55. url: this.videoUrl || '',
  56. poster: this.poster || ''
  57. }
  58. }
  59. },
  60. methods: {
  61. pause() {
  62. // #ifdef MP-WEIXIN
  63. try {
  64. const c = uni.createVideoContext(this.playerId, this)
  65. if (c && c.pause) c.pause()
  66. } catch (e) {}
  67. // #endif
  68. // #ifndef MP-WEIXIN
  69. this.fcXgPauseCmd = Date.now()
  70. // #endif
  71. }
  72. }
  73. }
  74. </script>
  75. <script module="fcXgRender" lang="renderjs">
  76. const XG_SCRIPT = 'https://unpkg.byted-static.com/xgplayer/3.0.20/dist/index.min.js';
  77. const XG_CSS = 'https://unpkg.byted-static.com/xgplayer/3.0.20/dist/index.min.css';
  78. export default {
  79. data() {
  80. return {
  81. player: null,
  82. lastConfig: null
  83. };
  84. },
  85. beforeDestroy() {
  86. this._destroyPlayer();
  87. },
  88. methods: {
  89. _ensureXgAssets(cb) {
  90. const run = () => {
  91. this._ensureStyles();
  92. cb();
  93. };
  94. if (typeof window.Player === 'function') {
  95. run();
  96. return;
  97. }
  98. if (window.__fcXgScriptLoading) {
  99. window.__fcXgScriptLoading.then(run);
  100. return;
  101. }
  102. window.__fcXgScriptLoading = new Promise((resolve) => {
  103. if (!document.querySelector('link[data-fc-xg-css]')) {
  104. const link = document.createElement('link');
  105. link.rel = 'stylesheet';
  106. link.href = XG_CSS;
  107. link.setAttribute('data-fc-xg-css', '1');
  108. document.head.appendChild(link);
  109. }
  110. const script = document.createElement('script');
  111. script.src = XG_SCRIPT;
  112. script.onload = () => resolve();
  113. script.onerror = () => resolve();
  114. document.head.appendChild(script);
  115. });
  116. window.__fcXgScriptLoading.then(run);
  117. },
  118. _ensureStyles() {
  119. if (document.querySelector('style[data-fc-xg-inline]')) return;
  120. const style = document.createElement('style');
  121. style.setAttribute('data-fc-xg-inline', '1');
  122. style.textContent = [
  123. '.fc-xg-player-host, .fc-xg-player-render, .fc-xg-player-inner {',
  124. ' width: 100% !important;',
  125. ' height: 100% !important;',
  126. ' min-height: 100% !important;',
  127. '}',
  128. '.fc-xg-player-host .xgplayer {',
  129. ' width: 100% !important;',
  130. ' height: 100% !important;',
  131. ' min-height: 100% !important;',
  132. '}',
  133. '.fc-xg-player-host .xgplayer video {',
  134. ' width: 100% !important;',
  135. ' height: 100% !important;',
  136. ' object-fit: fill !important;',
  137. '}'
  138. ].join('\n');
  139. document.head.appendChild(style);
  140. },
  141. _destroyPlayer() {
  142. if (!this.player) return;
  143. try {
  144. this.player.destroy();
  145. } catch (e) {}
  146. this.player = null;
  147. },
  148. _shouldReinit(newValue, oldValue) {
  149. if (!this.player || !oldValue || !newValue) return true;
  150. return newValue.url !== oldValue.url || newValue.playerId !== oldValue.playerId;
  151. },
  152. _waitDom(playerId, cb, attempt = 0) {
  153. const el = document.getElementById(playerId);
  154. if (el) {
  155. cb(el);
  156. return;
  157. }
  158. if (attempt >= 30) return;
  159. setTimeout(() => this._waitDom(playerId, cb, attempt + 1), 80);
  160. },
  161. _initPlayer(config) {
  162. const Player = window.Player;
  163. if (!Player || !config || !config.url || !config.playerId) return;
  164. const playerId = config.playerId;
  165. if (this.player && !this._shouldReinit(config, this.lastConfig)) {
  166. this.lastConfig = config;
  167. return;
  168. }
  169. this._destroyPlayer();
  170. this.lastConfig = config;
  171. const option = {
  172. lang: 'zh',
  173. url: config.url,
  174. id: playerId,
  175. autoplay: false,
  176. loop: false,
  177. height: '100%',
  178. width: '100%',
  179. poster: config.poster || '',
  180. playsinline: true,
  181. videoFillMode: 'fill',
  182. controls: false,
  183. ignores: [
  184. 'progress',
  185. 'volume',
  186. 'time',
  187. 'play',
  188. 'start',
  189. 'definition',
  190. 'fullscreen',
  191. 'miniplayer',
  192. 'miniscreen',
  193. 'keyboard',
  194. 'playbackrate'
  195. ],
  196. disableGesture: true,
  197. closeVideoTouch: true,
  198. closeVideoDblclick: true,
  199. closeVideoClick: true
  200. };
  201. this.player = new Player(option);
  202. },
  203. onConfig(newValue, oldValue) {
  204. if (!newValue || !newValue.url) {
  205. this._destroyPlayer();
  206. this.lastConfig = null;
  207. return;
  208. }
  209. this._ensureXgAssets(() => {
  210. this._waitDom(newValue.playerId, () => {
  211. this._initPlayer(newValue);
  212. });
  213. });
  214. },
  215. onPause() {
  216. if (this.player && this.player.pause) {
  217. try {
  218. this.player.pause();
  219. } catch (e) {}
  220. }
  221. }
  222. }
  223. };
  224. </script>
  225. <style scoped lang="scss">
  226. .fc-xg-player-host {
  227. width: 100%;
  228. height: 100%;
  229. min-height: 180rpx;
  230. display: block;
  231. overflow: hidden;
  232. }
  233. .fc-xg-player-render,
  234. .fc-xg-player-inner {
  235. width: 100%;
  236. height: 100%;
  237. min-height: 180rpx;
  238. }
  239. .fc-xg-player-mp-video {
  240. width: 100%;
  241. height: 100%;
  242. min-height: 180rpx;
  243. display: block;
  244. }
  245. </style>