index.tsx 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. import { defineComponent, PropType } from 'vue';
  2. import styles from './index.module.less';
  3. import Plyr from 'plyr';
  4. import 'plyr/dist/plyr.css';
  5. import { Loading } from 'vant';
  6. import { browser } from '@/helpers/utils';
  7. export default defineComponent({
  8. name: 'm-video',
  9. props: {
  10. setting: {
  11. type: Object,
  12. default: () => ({})
  13. },
  14. controls: Boolean,
  15. height: String,
  16. src: {
  17. type: String,
  18. default: ''
  19. },
  20. poster: {
  21. type: String,
  22. default: ''
  23. },
  24. styleValue: {
  25. type: Object,
  26. default: () => ({})
  27. },
  28. preload: {
  29. type: String as PropType<'auto' | 'metadata' | 'none'>,
  30. default: 'auto'
  31. },
  32. currentTime: {
  33. type: Boolean,
  34. default: true
  35. },
  36. playsinline: {
  37. type: Boolean,
  38. default: true
  39. },
  40. preLoading: {
  41. type: Boolean,
  42. default: true
  43. }
  44. // onPlay: {
  45. // type: Function,
  46. // default: () => {}
  47. // }
  48. },
  49. emits: ['exitfullscreen', 'play', 'ready', 'enterfullscreen'],
  50. data() {
  51. return {
  52. player: null as any,
  53. loading: true // 首次进入加载中
  54. };
  55. },
  56. mounted() {
  57. this.loading = this.preLoading;
  58. this._init();
  59. },
  60. methods: {
  61. _init() {
  62. // controls: [
  63. // 'play-large' , // 中间的大播放按钮
  64. // 'restart' , // 重新开始播放
  65. // 'rewind' , // 按寻道时间倒带(默认 10 秒)
  66. // 'play' , // 播放/暂停播放
  67. // 'fast-forward' , // 快进查找时间(默认 10 秒)
  68. // 'progress' , // 播放和缓冲的进度条和滑动条
  69. // 'current-time' , // 播放的当前时间
  70. // ' duration' , // 媒体的完整持续时间
  71. // 'mute' , // 切换静音
  72. // 'volume', // 音量控制
  73. // 'captions' , // 切换字幕
  74. // 'settings' , // 设置菜单
  75. // 'pip' , // 画中画(当前仅 Safari)
  76. // 'airplay' , // Airplay(当前仅 Safari)
  77. // 'download ' , // 显示一个下载按钮,其中包含指向当前源或您在选项中指定的自定义 URL 的链接
  78. // 'fullscreen' , // 切换全屏
  79. // ] ;
  80. const controls = [
  81. 'play-large',
  82. 'play',
  83. 'progress',
  84. 'captions',
  85. 'fullscreen'
  86. ];
  87. // if (browser().isApp) {
  88. // controls.push('fullscreen');
  89. // }
  90. if (this.currentTime) {
  91. controls.push('current-time');
  92. }
  93. const params: any = {
  94. controls: controls,
  95. ...this.setting,
  96. invertTime: false
  97. };
  98. if (browser().iPhone) {
  99. params.fullscreen = {
  100. enabled: true,
  101. fallback: 'force',
  102. iosNative: true
  103. };
  104. }
  105. this.player = new Plyr((this as any).$refs.video, params);
  106. // fullscreen: {
  107. // enabled: true,
  108. // fallback: 'force',
  109. // iosNative: true
  110. // }
  111. this.player.elements.container
  112. ? (this.player.elements.container.style.height = this.height || '210px')
  113. : null;
  114. if (this.preload === 'none') {
  115. this.loading = false;
  116. }
  117. this.player.on('loadedmetadata', () => {
  118. this.loading = false;
  119. this.domPlayVisibility(false);
  120. });
  121. this.player.on('loadeddata', () => {
  122. this.$emit('ready', this.player);
  123. });
  124. this.player.on('play', () => {
  125. this.$emit('play', this.player);
  126. });
  127. this.player.on('enterfullscreen', () => {
  128. // console.log('fullscreen', this.player.elements);
  129. // const fragment = document.createDocumentFragment();
  130. // const i = document.createElement('i');
  131. // i.id = 'fullscreen-back';
  132. // i.className = 'van-icon van-icon-arrow-left video-back';
  133. // i.addEventListener('click', () => {
  134. // this.player.fullscreen.exit();
  135. // });
  136. // console.log(document.getElementsByClassName('plyr'), i);
  137. // fragment.appendChild(i);
  138. // // const parentNode = document.getElementsByClassName('plyr')[0];
  139. // // parentNode.insertBefore(fragment, parentNode.firstChild);
  140. // this.player.elements.container.appendChild(fragment);
  141. this.$emit('enterfullscreen');
  142. });
  143. this.player.on('exitfullscreen', () => {
  144. console.log('exitfullscreen');
  145. // const i = document.getElementById('fullscreen-back');
  146. // i && i.remove();
  147. this.$emit('exitfullscreen');
  148. });
  149. },
  150. // 操作功能
  151. domPlayVisibility(hide = true) {
  152. const controls = document.querySelector('.plyr__controls');
  153. const controls2 = document.querySelector('.plyr__control--overlaid');
  154. if (hide) {
  155. controls?.setAttribute('style', 'display:none');
  156. controls2?.setAttribute('style', 'display:none');
  157. } else {
  158. controls?.removeAttribute('style');
  159. setTimeout(() => {
  160. controls2?.removeAttribute('style');
  161. }, 200);
  162. }
  163. },
  164. onStop() {
  165. this.player.stop();
  166. },
  167. onExitScreen() {
  168. this.player.fullscreen.active && this.player.fullscreen.exit();
  169. },
  170. onPlay() {
  171. this.player?.play();
  172. }
  173. },
  174. unmounted() {
  175. this.player?.destroy();
  176. },
  177. render() {
  178. return (
  179. <div class={styles['video-container']}>
  180. <video
  181. ref="video"
  182. class={styles['video']}
  183. src={this.src}
  184. playsinline={this.playsinline}
  185. poster={this.poster}
  186. preload={this.preload}
  187. style={{ ...this.styleValue }}></video>
  188. {/* </div> */}
  189. {/* 加载视频使用 */}
  190. {this.loading && (
  191. <div
  192. class={styles.loadingVideo}
  193. style={{
  194. height: this.height || '210px'
  195. }}>
  196. <Loading
  197. size={36}
  198. color="#FF8057"
  199. vertical
  200. style={{ height: '100%', justifyContent: 'center' }}>
  201. 加载中...
  202. </Loading>
  203. </div>
  204. )}
  205. </div>
  206. );
  207. }
  208. });