Browse Source

视频优化

yewenwen 6 years ago
parent
commit
b90cf33acd
3 changed files with 286 additions and 47 deletions
  1. 82 13
      src/packages/video/video.scss
  2. 172 34
      src/packages/video/video.vue
  3. 32 0
      src/utils/throttle.js

+ 82 - 13
src/packages/video/video.scss

@@ -16,25 +16,27 @@
     }
     .nut-video-play-btn {
         // display: none;
-        top: 50%;
-        left: 50%;
-        margin-left: -1em;
-        width: 2em;
+        width: 80px;
+        height: 50px;
+        margin-top: -25px;
+        display: flex;
+        align-items: center;
+        justify-content: center;
         border: 0;
-        background-color: rgba(0, 0, 0, .45);
+        background-color: rgba(0, 0, 0, 0.45);
         color: #fff;
-        transition: border-color .4s, outline .4s, background-color .4s;
+        transition: border-color 0.4s, outline 0.4s, background-color 0.4s;
         position: absolute;
+        top: 50%;
+        left: 50%;
+        margin-left: -40px;
         padding: 0;
         cursor: pointer;
         opacity: 1;
-        background-color: rgba(0, 0, 0, .5);
-        font-size: 2.5em;
+        background-color: rgba(0, 0, 0, 0.5);
+        font-size: 30px;
         border-radius: 20%;
-        height: 1.4em;
-        line-height: 1.4em;
-        margin-top: -.7em;
-        text-align: center;
+
         &:hover {
             background-color: #cc181e;
         }
@@ -47,4 +49,71 @@
             background-size: contain;
         }
     }
-}
+    .nut-video-controller {
+        position: absolute;
+        display: flex;
+        left: 0;
+        bottom: 0;
+        background-color: rgba(0, 0, 0, 1);
+        height: 35px;
+        width: 100%;
+        z-index: 11111111;
+        align-items: center;
+        .duration-time,
+        .current-time {
+            color: #fff;
+            padding: 0 5px;
+            font-size: 14px;
+        }
+        .progress-container {
+            position: relative;
+            display: inline-block;
+            height: 100%;
+            width: 100%;
+            overflow: hidden;
+            margin: 0 10px;
+            transition: all 0.2s ease-in;
+            flex: 1;
+            .progress {
+                position: absolute;
+                top: 50%;
+                width: 100%;
+                height: 2px;
+                margin-top: -0.05rem;
+                background: rgba(255, 255, 255, 0.5);
+                // overflow: hidden;
+            }
+            .buffered {
+                background: rgba(255, 255, 255, 0.8);
+                height: 2px;
+            }
+            .video-ball {
+                width: 15px;
+                height: 15px;
+                background: #fff;
+                box-shadow: 0px 0px 2px 0px rgba(0, 0, 0, 0.2);
+                position: absolute;
+                top: -6px;
+                left: 50%;
+                margin-left: -7px;
+                border-radius: 50%;
+            }
+        }
+        .fullscreen-icon {
+            width: 40px;
+            height: 35px;
+            background: url('../../assets/img/video-icon.png') no-repeat;
+            background-size: 218px 38px;
+            background-position: -71px 0px;
+        }
+    }
+}
+// ::-webkit-media-controls {
+//     display: none !important;
+// }
+// video::-webkit-media-controls {
+//     display: none !important;
+// }
+// video::-webkit-media-controls-enclosure {
+//     display: none !important;
+// }

+ 172 - 34
src/packages/video/video.vue

@@ -7,15 +7,31 @@
             :muted="options.muted"
             :autoplay="options.autoplay"
             :loop="options.loop"
-            :controls="options.controls"
             :poster="options.poster"
+            :controls="options.controls"
             @error="handleError"
+            @canplaythrough="state.isLoading = false"
         >
             <source v-for="source in sources" :src="source.src" :type="source.type" :key="source.src" />
         </video>
         <div class="playing-mask" @click="play"></div>
         <div class="nut-video-play-btn" v-show="!state.playing" @click="play"></div>
-        <div class="nut-video-controller"></div>
+        <div class="nut-video-controller" v-show="showToolbox">
+            <!-- <div class="control-button" :class="{pause:isPlay,play:!isPlay}" @click="playOrPause"></div> -->
+            <div class="current-time">{{ videoSet.displayTime }}</div>
+            <div class="progress-container">
+                <div class="progress" ref="progressBar">
+                    <div class="buffered" style="width:50%"></div>
+                    <div class="video-ball">
+                        <div></div>
+                    </div>
+                    <div class="played" ref="playedBar"></div>
+                </div>
+            </div>
+            <div class="duration-time">{{ videoSet.totalTime }}</div>
+            <div class="volume"></div>
+            <div class="fullscreen-icon" @click="fullScreen"></div>
+        </div>
         <!-- 错误弹窗 -->
         <div class="nut-video-error" v-show="state.isError">
             <p class="lose">视频加载失败</p>
@@ -24,6 +40,7 @@
     </div>
 </template>
 <script>
+import {throttle} from '../../utils/throttle';
 export default {
     name: 'nut-video',
     props: {
@@ -45,8 +62,7 @@ export default {
                     controls: true,
                     muted: false, //是否静音
                     disabled: false, //禁止操作
-                    playsinline: false, //行内展示
-                    
+                    playsinline: false //行内展示
                 };
             },
             required: true
@@ -54,11 +70,29 @@ export default {
     },
     data() {
         return {
-            video: null,
+            videoElm: null,
             initial: true, //控制封面的显示
             showToolbox: false, //控制控制器和标题的显示
-            progress: 0, //进度
-            duration: 0, //总时长
+            // 视频容器元素
+            player: {
+                $player: null,
+                pos: null
+            },
+            // progress进度条元素
+            progressBar: {
+                progressElm: null, // 进度条DOM对象
+                pos: null
+            },
+            // video控制显示设置
+            videoSet: {
+                loaded: 0, // 缓存长度
+                displayTime: '00:00', // 进度时间
+                totalTime: '00:00', // 总时间
+                progress: {
+                    width: 0, // 进度条长度
+                    current: 0 // 进度条当前位置
+                }
+            },
             state: {
                 contrlShow: true,
                 vol: 0.5, //音量
@@ -73,70 +107,174 @@ export default {
     },
     mounted() {
         this.init();
+
+        // this.videoDome.addEventListener('progress', () => {
+        //     setTimeout(() => {
+        //         let v = this.videoDome;
+        //         let r = v.buffered;
+        //         let total = v.duration;
+        //         try {
+        //             let end = r.end(0);
+        //             this.videoTime = total;
+        //             this.videoMetadata = (end / total) * 100;
+        //         } catch (e) {
+        //         }
+        //     }, 100)
+        // }, false);
+        // this.videoDome.addEventListener('seeked', () => {
+        //     if (this.videoDome.readyState >= 2) {
+        //         this.isLoading = false;
+        //     }
+        // });
+        // this.videoDome.addEventListener('waiting', _ => {
+        //     this.isLoading = true;
+        // })
     },
     methods: {
         init() {
-            this.video = this.$el.getElementsByTagName('video')[0]
+            this.videoElm = this.$el.getElementsByTagName('video')[0];
             if (this.options.autoplay) {
                 this.play();
             }
 
             if (this.options.playsinline) {
-                this.video.setAttribute('playsinline', this.options.playsinline);
-                this.video.setAttribute('webkit-playsinline', this.options.playsinline);
-                this.video.setAttribute('x5-playsinline', this.options.playsinline);
-                this.video.setAttribute('x5-video-player-type', 'h5');
-                this.video.setAttribute('x5-video-player-fullscreen', false);
+                this.videoElm.setAttribute('playsinline', this.options.playsinline);
+                this.videoElm.setAttribute('webkit-playsinline', this.options.playsinline);
+                this.videoElm.setAttribute('x5-playsinline', this.options.playsinline);
+                this.videoElm.setAttribute('x5-video-player-type', 'h5');
+                this.videoElm.setAttribute('x5-video-player-fullscreen', false);
             }
             this.volumeHandle();
-            
-            this.video.addEventListener('play', ()=>{
+
+            // const $player = this.$el;
+            // const $progress = this.$el.getElementsByClassName('progress')[0];
+            // // 播放器位置
+            // this.player.$player = $player;
+            // this.progressBar.$progress = $progress;
+            // this.player.pos = $player.getBoundingClientRect();
+            // this.progressBar.pos = $progress.getBoundingClientRect();
+            // this.videoSet.progress.width = Math.round($progress.getBoundingClientRect().width);
+
+            this.videoElm.addEventListener('play', () => {
                 this.state.playing = true;
             });
-            this.video.addEventListener('pause', ()=>{
+            this.videoElm.addEventListener('pause', () => {
                 this.state.playing = false;
             });
         },
         play() {
             this.state.playing = !this.state.playing;
-            
+
             if (this.options.autoplay && this.options.disabled) {
                 this.state.playing = true;
                 return false;
             }
-            if (this.video) {
+            if (this.videoElm) {
+                // if (this.state.playing) {
+                //     this.videoElm.play();
+                //     this.videoElm.addEventListener('ended', this.playEnded);
+                //     this.$emit('play', this.video);
+                // } else {
+                //     this.videoElm.pause();
+                //     this.$emit('pause', this.video);
+                // }
+                // 播放状态
                 if (this.state.playing) {
-                    this.video.play();
-                    this.video.addEventListener('ended', this.playEnded);
-                    this.$emit('play', this.video)
-                    
-                } else {
-                    this.video.pause();
-                    this.$emit('pause', this.video)
+                    try {
+                        this.videoElm.play();
+                        // this.isPauseTouch = false;
+                        // 监听缓存进度
+                        // this.videoElm.addEventListener('progress', e => {
+                        //     this.getLoadTime();
+                        // });
+                        // // 监听播放进度
+                        // this.videoElm.addEventListener('timeupdate', throttle(this.getPlayTime, 100, 1));
+                        // 监听结束
+                        this.videoElm.addEventListener('ended', this.playEnded);
+                        this.$emit('play', this.video);
+                    } catch (e) {
+                        // 捕获url异常出现的错误
+                    }
+                }
+                // 停止状态
+                else {
+                    this.isPauseTouch = true;
+                    this.videoElm.pause();
+                    this.$emit('pause', this.video);
                 }
             }
         },
-        volumeHandle(){
-            this.state.vol = this.video.volume
+        volumeHandle() {
+            this.state.vol = this.videoElm.volume;
         },
-        playEnded(){
-            this.state.playing = false;
-            this.video.currentTime = 0;
+        playEnded() {
             // console.log('ended')
-            this.$emit('playend', this.video)
+            this.state.playing = false;
+            this.state.isEnd = true;
+            this.state.controlBtnShow = true;
+            this.videoSet.displayTime = '00:00';
+            this.videoSet.progress.current = 0;
+            this.videoElm.currentTime = 0;
+            this.$emit('playend', this.videoElm);
         },
         // 数据加载出错
         handleError() {
             // console.log('error')
             this.state.isError = true;
         },
+
+        fullScreen() {
+            const isFullscreen = document.webkitIsFullScreen || document.fullscreen;
+            if (isFullscreen) {
+                const exitFunc = document.exitFullscreen || document.webkitExitFullscreen;
+                exitFunc.call(document);
+            } else {
+                const element = this.videoElm;
+                const fullscreenFunc = element.requestFullscreen || element.webkitRequestFullScreen;
+                fullscreenFunc.call(element);
+            }
+
+            // if (!this.state.fullScreen) {
+            //     this.state.fullScreen = true;
+            //     this.video.webkitRequestFullScreen();
+            // } else {
+            //     this.state.fullScreen = false;
+            //     document.webkitCancelFullScreen();
+            // }
+            // setTimeout(this.initVideo, 200);
+        },
+        // 获取播放时间
+        getPlayTime() {
+            console.log(222);
+            const percent = this.videoElm.currentTime / this.videoElm.duration;
+            this.videoSet.progress.current = Math.round(this.videoSet.progress.width * percent);
+            // 赋值时长
+            this.videoSet.totalTime = timeParse(this.videoElm.duration);
+            this.videoSet.displayTime = timeParse(this.videoElm.currentTime);
+        },
+        // 获取缓存时间
+        getLoadTime() {
+            // console.log('缓存了...',this.videoElm.buffered.end(0));
+            this.videoSet.loaded = (this.videoElm.buffered.end(0) / this.videoElm.duration) * 100;
+        },
+        getTime() {
+            this.videoElm.addEventListener('durationchange', e => {
+                console.log(e);
+            });
+            this.videoElm.addEventListener('progress', e => {
+                this.videoSet.loaded = (-1 + this.videoElm.buffered.end(0) / this.videoElm.duration) * 100;
+            });
+            this.videoSet.len = this.videoElm.duration;
+        },
+        sliderStart() {},
+        touchmove() {},
+        touchend() {},
         // 点击重新加载
         retry() {
             this.state.isError = false;
             this.init();
-        },
+        }
     },
-    beforeDestroy() {
-    }
+    beforeDestroy() {}
 };
 </script>

+ 32 - 0
src/utils/throttle.js

@@ -0,0 +1,32 @@
+/**
+ * @desc 函数节流
+ * @param func 函数
+ * @param wait 延迟执行毫秒数
+ * @param type 1 表时间戳版,2 表定时器版
+ */
+export const throttle = (func, wait, type) => {
+    if (type === 1) {
+        var previous = 0;
+    } else if (type === 2) {
+        var timeout;
+    }
+    return function() {
+        let context = this;
+        let args = arguments;
+        if (type === 1) {
+            let now = Date.now();
+
+            if (now - previous > wait) {
+                func.apply(context, args);
+                previous = now;
+            }
+        } else if (type === 2) {
+            if (!timeout) {
+                timeout = setTimeout(() => {
+                    timeout = null;
+                    func.apply(context, args);
+                }, wait);
+            }
+        }
+    };
+};