backup.vue 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267
  1. <template>
  2. <div class="nut-video" ref="videocon">
  3. <video
  4. ref="video"
  5. class="nut-videoplayer"
  6. type="video/mp4"
  7. :muted="options.muted"
  8. :autoplay="options.autoplay"
  9. :loop="options.loop"
  10. :poster="options.poster"
  11. :controls="options.controls"
  12. @error="handleError"
  13. >
  14. <source v-for="source in sources" :src="source.src" :type="source.type" :key="source.src" />
  15. </video>
  16. <div class="playing-mask" ref="touchMask" v-if="showTouchMask" @click="play"></div>
  17. <!-- <div class="nut-video-play-btn" ref="palyBtn" v-show="!state.playing" @click="play"></div> -->
  18. <!-- <div class="nut-video-controller" v-show="showToolbox">
  19. <div class="current-time">{{ videoSet.displayTime }}</div>
  20. <div class="progress-container">
  21. <div class="progress" ref="progressBar">
  22. <div class="buffered" style="width:50%"></div>
  23. <div class="video-ball">
  24. <div></div>
  25. </div>
  26. <div class="played" ref="playedBar"></div>
  27. </div>
  28. </div>
  29. <div class="duration-time">{{ videoSet.totalTime }}</div>
  30. <div class="volume"></div>
  31. <div class="fullscreen-icon" @click="fullScreen"></div>
  32. </div> -->
  33. <!-- 错误弹窗 -->
  34. <div class="nut-video-error" v-show="state.isError">
  35. <p class="lose">视频加载失败</p>
  36. <p class="retry" @click="retry">点击重试</p>
  37. </div>
  38. </div>
  39. </template>
  40. <script>
  41. import { throttle } from '../../utils/throttle';
  42. export default {
  43. name: 'nut-video',
  44. props: {
  45. src: '',
  46. playsinline: {
  47. type: Boolean,
  48. default: false
  49. },
  50. sources: Array,
  51. options: {
  52. type: Object,
  53. default() {
  54. return {
  55. autoplay: false, //是否自动播放
  56. volume: 0.5,
  57. poster: '',
  58. loop: false,
  59. controls: true,
  60. muted: false, //是否静音
  61. disabled: false, //禁止操作
  62. playsinline: false, //行内展示
  63. touchPlay: false
  64. };
  65. },
  66. required: true
  67. }
  68. },
  69. data() {
  70. return {
  71. videoElm: null,
  72. initial: true, //控制封面的显示
  73. showToolbox: false, //控制控制器和标题的显示
  74. // 视频容器元素
  75. player: {
  76. $player: null,
  77. pos: null
  78. },
  79. // progress进度条元素
  80. progressBar: {
  81. progressElm: null, // 进度条DOM对象
  82. pos: null
  83. },
  84. // video控制显示设置
  85. videoSet: {
  86. loaded: 0, // 缓存长度
  87. displayTime: '00:00', // 进度时间
  88. totalTime: '00:00', // 总时间
  89. progress: {
  90. width: 0, // 进度条长度
  91. current: 0 // 进度条当前位置
  92. }
  93. },
  94. state: {
  95. contrlShow: false,
  96. vol: 0.5, //音量
  97. currentTime: 0, //当前时间
  98. fullScreen: false,
  99. playing: false, //是否正在播放
  100. isLoading: false,
  101. isEnd: false,
  102. isError: false
  103. },
  104. showTouchMask: false
  105. };
  106. },
  107. watch: {
  108. sources: {
  109. handler(newValue, oldValue) {
  110. if (newValue && oldValue && newValue != oldValue) {
  111. this.$nextTick(() => {
  112. this.videoElm.load();
  113. });
  114. }
  115. },
  116. immediate: true
  117. },
  118. options: {
  119. handler(val) {},
  120. immediate: true
  121. }
  122. },
  123. mounted() {
  124. this.init();
  125. },
  126. methods: {
  127. init() {
  128. this.videoElm = this.$el.getElementsByTagName('video')[0];
  129. if (this.options.autoplay) {
  130. this.play();
  131. }
  132. if (this.options.touchPlay) {
  133. this.showTouchMask = true;
  134. }
  135. if (this.options.playsinline) {
  136. this.videoElm.setAttribute('playsinline', this.options.playsinline);
  137. this.videoElm.setAttribute('webkit-playsinline', this.options.playsinline);
  138. this.videoElm.setAttribute('x5-playsinline', this.options.playsinline);
  139. this.videoElm.setAttribute('x5-video-player-type', 'h5');
  140. this.videoElm.setAttribute('x5-video-player-fullscreen', false);
  141. }
  142. this.volumeHandle();
  143. // const $player = this.$el;
  144. // const $progress = this.$el.getElementsByClassName('progress')[0];
  145. // // 播放器位置
  146. // this.player.$player = $player;
  147. // this.progressBar.$progress = $progress;
  148. // this.player.pos = $player.getBoundingClientRect();
  149. // this.progressBar.pos = $progress.getBoundingClientRect();
  150. // this.videoSet.progress.width = Math.round($progress.getBoundingClientRect().width);
  151. this.videoElm.addEventListener('play', () => {
  152. this.state.playing = true;
  153. });
  154. this.videoElm.addEventListener('pause', () => {
  155. this.state.playing = false;
  156. });
  157. },
  158. play() {
  159. this.state.playing = !this.state.playing;
  160. if (this.options.autoplay && this.options.disabled) {
  161. this.state.playing = true;
  162. return false;
  163. }
  164. if (this.videoElm) {
  165. // if (this.state.playing) {
  166. // this.videoElm.play();
  167. // this.videoElm.addEventListener('ended', this.playEnded);
  168. // this.$emit('play', this.video);
  169. // } else {
  170. // this.videoElm.pause();
  171. // this.$emit('pause', this.video);
  172. // }
  173. // 播放状态
  174. if (this.state.playing) {
  175. try {
  176. this.videoElm.play();
  177. // this.isPauseTouch = false;
  178. // 监听缓存进度
  179. // this.videoElm.addEventListener('progress', e => {
  180. // this.getLoadTime();
  181. // });
  182. // // 监听播放进度
  183. // this.videoElm.addEventListener('timeupdate', throttle(this.getPlayTime, 100, 1));
  184. // 监听结束
  185. this.videoElm.addEventListener('ended', this.playEnded);
  186. this.$emit('play', this.videoElm);
  187. } catch (e) {
  188. // 捕获url异常出现的错误
  189. this.handleError();
  190. }
  191. }
  192. // 停止状态
  193. else {
  194. // this.isPauseTouch = true;
  195. this.videoElm.pause();
  196. this.$emit('pause', this.videoElm);
  197. }
  198. }
  199. },
  200. volumeHandle() {
  201. this.state.vol = this.videoElm.volume;
  202. },
  203. playEnded() {
  204. console.log('ended', this.videoSet.displayTime);
  205. this.state.playing = false;
  206. this.state.isEnd = true;
  207. this.state.controlBtnShow = true;
  208. this.videoSet.displayTime = '00:00';
  209. this.videoSet.progress.current = 0;
  210. this.videoElm.currentTime = 0;
  211. this.$emit('playend', this.videoElm);
  212. },
  213. // 数据加载出错
  214. handleError() {
  215. // console.log('error')
  216. this.state.isError = true;
  217. },
  218. fullScreen() {
  219. if (!this.state.fullScreen) {
  220. this.state.fullScreen = true;
  221. this.video.webkitRequestFullScreen();
  222. } else {
  223. this.state.fullScreen = false;
  224. document.webkitCancelFullScreen();
  225. }
  226. setTimeout(this.initVideo, 200);
  227. },
  228. // 获取播放时间
  229. getPlayTime() {
  230. const percent = this.videoElm.currentTime / this.videoElm.duration;
  231. this.videoSet.progress.current = Math.round(this.videoSet.progress.width * percent);
  232. // 赋值时长
  233. this.videoSet.totalTime = timeParse(this.videoElm.duration);
  234. this.videoSet.displayTime = timeParse(this.videoElm.currentTime);
  235. },
  236. // 获取缓存时间
  237. getLoadTime() {
  238. // console.log('缓存了...',this.videoElm.buffered.end(0));
  239. this.videoSet.loaded = (this.videoElm.buffered.end(0) / this.videoElm.duration) * 100;
  240. },
  241. getTime() {
  242. this.videoElm.addEventListener('durationchange', e => {
  243. console.log(e);
  244. });
  245. this.videoElm.addEventListener('progress', e => {
  246. this.videoSet.loaded = (-1 + this.videoElm.buffered.end(0) / this.videoElm.duration) * 100;
  247. });
  248. this.videoSet.len = this.videoElm.duration;
  249. },
  250. sliderStart() {},
  251. touchmove() {},
  252. touchend() {},
  253. // 点击重新加载
  254. retry() {
  255. console.log('error');
  256. this.state.isError = false;
  257. this.init();
  258. }
  259. },
  260. beforeDestroy() {}
  261. };
  262. </script>