H5 create their own video player (JS Part 2)

review

Well not reviewed directly huh, open JS1 in writing bvd.jsclipboard.png

Play Video

  1. Play button hidden

  2. Video starts playing
    when click the play button, a play button will be hidden, play the video, this is not difficult, in JS1 we have achieved. But we have a change of thinking, tap to add a click event video, video players, and then play event is triggered, so that the play button hidden

    pro.initEvent = function(){
        var that = this;
    
        //给播放按钮图片添加事件
        this.vimg.addEventListener('tap',function(){
            that.video.play();
        })
    
        //视频点击暂停或播放事件
        this.video.addEventListener('tap',function(){
            if(this.paused || this.ended) {
                //暂停时点击就播放
                if(this.ended) {//如果播放完毕,就重头开始播放
                    this.currentTime = 0;
                }
                this.play();
            } else {
                //播放时点击就暂停
                this.pause();
            }
        })
        
        //视频播放事件
        this.video.addEventListener('play',function(){
            that.vimg.style.display = 'none';
        })
        
        
        //获取到元数据
        this.video.addEventListener('loadedmetadata',function(){
            that.vC.querySelector('.duration').innerHTML = stom(this.duration);
        });
    }
  3. Hidden below the control bar gradually
    hiding is not the difficulty, it is important to gradually hidden, so here we have several solutions:

    1. Timer

    2. css3 animation frames

Here we have two kinds in combinationclipboard.png

First, let's define a good set of animation

@keyframes vhide {0% {opacity: 1;}100% {opacity: 0;}}

@-webkit-keyframes vhide {0% {opacity: 1;}100% {opacity: 0;}}

.vhidden {
    animation: vhide 3.5s ease-in;
    -webkit-animation: vhide 3.5s ease-in;
}

Its role is transparency 1 => 0, ease-in effect is excessively fast from slow to 3.5 seconds. Css animations do not understand you can ask of your mother oh
and then we start playing the video when the event to the control bar added vhidden style class

//视频播放事件
this.video.addEventListener('play',function(){
    that.vC.classList.add('vhidden');
})

Test results, and sure enough within 3.5s, control bar slowly clear, the problem is after 3.5s, transparency back to the 1, and here I explain, because the animation frames by default is rebound, we can add style

.vhidden {
    animation: vhide 3.5s ease-in;
    -webkit-animation: vhide 3.5s ease-in;
    animation-fill-mode:forwards;
    -webkit-animation-fill-mode: forwards;
}

CSS3 animation-fill-mode attribute is used to define elements like after the animation.

The default value of animation-fill-mode is none, that is, without any changes after the end of the animation, if after the end of the animation-fill-mode forwards into the animation style elements will become the last key frame animation specified style.

After adding this style, and sure enough after 3.5s, the animation will not rebound, but here to look at, but transparent control bar is not gone, and if we have to write then click on the control bar of the time, so in control click the bar position, or will trigger events, so, we can write for a setTimeout to allow the control bar to hide after 3.5s, this we can choose their own

//视频播放事件
this.video.addEventListener('play',function(){
    that.vimg.style.display = 'none';
    that.vC.classList.add('vhidden');
    that.vCt = setTimeout(function(){
        that.vC.style.visibility = 'hidden';
    },3400);
})

Why animation process is 3.5s, but the implementation is js after 3.4s, not just here to write animation-fill-mode: forwards the case to be insured

clipboard.png

Playing in

Hey, you can play video! So now that we think about playing what things to do?

1. Control bar progress bar slowly grow

We need to add a video timeupdate event audio and video playback position is changed

Let's get the video metadata in the event, the length of the video to win

//获取到元数据
this.video.addEventListener('loadedmetadata',function(){
    that.vDuration = this.duration;
    that.vC.querySelector('.duration').innerHTML = stom(that.vDuration);
});

Then calculate the ratio, set the progress bar from the video playback progress update event in width

//视频播放中事件
this.video.addEventListener('timeupdate', function() {
    var currentPos = this.currentTime;//获取当前播放的位置
    //更新进度条
    var percentage = 100 * currentPos / that.vDuration; 
    //设置宽度
    that.vC.querySelector('.timeBar').style.width = percentage + '%';
});

clipboard.png

We can see the progress bar Jun increasingly inflated.

2. The current playing time

At the same time, we also display the currently playing time timeupdate event set

//视频播放中事件
this.video.addEventListener('timeupdate', function() {
    var currentPos = this.currentTime;//获取当前播放的位置
    //更新进度条
    var percentage = 100 * currentPos / that.vDuration; 
    that.vC.querySelector('.timeBar').style.width = percentage + '%';
    //更新当前播放时间
    that.vC.querySelector('.current').innerHTML = stom(currentPos);
});

clipboard.png

Pause or Stop

When we click on the video, if it is to pause, then start playing, and playing the trigger event, whereas in video playback, click on the video will pause, and pause trigger event.

0. time frames

La la la, pause playback, timeupdate events naturally do not trigger it, so the progress bar and the current play time will not become friends.

1. Play button

In the pause when the show button to Come

//暂停or停止
this.video.addEventListener('pause',function(){
    that.vimg.style.display = 'block';
});

2 below the control bar display

Control bar display, direct removal of the vhidden style class Jiuhaola

//暂停or停止
this.video.addEventListener('pause',function(){
    that.vimg.style.display = 'block';
    that.vC.classList.remove('vhidden');
    that.vC.style.visibility = 'visible';
});

Write it seems to be true, but if you hide the control bar before the time to write a setTimeout, then this time we should clear out oh.

//暂停or停止
this.video.addEventListener('pause',function(){
    that.vimg.style.display = 'block';
    that.vC.classList.remove('vhidden');
    that.vC.style.visibility = 'visible'; 
    that.vCt && clearTimeout(that.vCt);
});

Fast forward and rewind

Diao Diao clatter of how a small video player may be less of a retreat into resilient it?

Come, let's add the left slide right slide event video

//视频手势右滑动事件
this.video.addEventListener('swiperight',function(e){
    this.currentTime += 5;
});
//视频手势左滑动事件
this.video.addEventListener('swipeleft',function(e){
    this.currentTime -= 5;
});

Debugging may progress directly on the computer becomes 0, at the beginning I also wonder what, later found webview on the phone seems to be feasible.

About the progress bar and drag to change the video progress I do not intend to write, because I did not write.clipboard.png

Full-screen playback

Perhaps we are more concerned about this right:

ios end: the removal of the video tag webkit-playsinline property can be, because of ios h5 support the video tag is quite good

//调用原生方式 全屏播放
pro.nativeMax = function(){
    if(!window.plus){
        //非html5+环境
        return;
    }
    if($.os.ios){
        console.log('ios')
        this.video.removeAttribute('webkit-playsinline');
    }else if($.os.android){
        console.log('android');
        var url = this.video.querySelector('source').src;
        var Intent = plus.android.importClass("android.content.Intent");
        var Uri = plus.android.importClass("android.net.Uri");
        var main = plus.android.runtimeMainActivity();
        var intent = new Intent(Intent.ACTION_VIEW);
        var uri = Uri.parse(url);
        intent.setDataAndType(uri, "video/*");
        main.startActivity(intent);
    }
}

Click to add full-screen events in initEvent

this.vC.querySelector('.fill').addEventListener('tap',function(){
    that.nativeMax();
});

Doing a bit tasteless ah, you can not point to a common?

The question I really want one night and decided to bring a little dry.

Give states the default for the mini player

var bvd = function(dom) {
    var that = this;
    $.ready(function() {
        //获取视频元素
        that.video = document.querySelector(dom || 'video');
        //获取视频父元素
        that.vRoom = that.video.parentNode;
        //元素初始化
        that.initEm();
        //事件初始化
        that.initEvent();
        //记录信息
        that.initInfo();
        //当前播放模式 false 为 mini播放
        that.isMax = false;
    })
}

//记录信息
pro.initInfo = function() {
    var that = this;
    //在onload状态下,offsetHeight才会获取到正确的值
    window.onload = function(){
        that.miniInfo = {//mini状态时的样式
            width: that.video.offsetWidth + 'px',
            height: that.video.offsetHeight + 'px',
            position: that.vRoom.style.position,
            transform: 'translate(0,0) rotate(0deg)'
        }

        var info = [
                document.documentElement.clientWidth || document.body.clientWidth,
                document.documentElement.clientHeight || document.body.clientHeigth
            ],
            w = info[0],
            h = info[1],
            cha = Math.abs(h - w) / 2;
            
        that.maxInfo = {//max状态时的样式
            width: h + 'px',
            height: w + 'px',
            position: 'fixed',
            transform: 'translate(-' + cha + 'px,' + cha + 'px) rotate(90deg)'
        }
    }
    
    
}

//全屏 mini 两种模式切换
pro.switch = function() {
    var vR = this.vRoom;
    //获取需要转换的样式信息
    var info = this.isMax ? this.miniInfo : this.maxInfo;
    for(var i in info) {
        vR.style[i] = info[i];
    }
    this.isMax = !this.isMax;
}

//全屏按钮
this.vC.querySelector('.fill').addEventListener('tap', function() {
    //that.nativeMax();
    that.switch();
});

Dude pull, pull a look

clipboard.png

Looks and feels very good too, using the displacement and rotation css3, so that video full-screen in the front of the screen, but the problem has cropped up

  • Play button and a control bar in full-screen seems to hide the fact that video labels cover the top of the parent element, we have to make corresponding adjustments

css

.bad-video {
    position: relative;
    /*overflow: hidden;*/
    background-color: #CCCCCC;
}

JS
max among the configuration set value zIndex

            that.maxInfo = {//max状态时的样式
                zIndex:99,
                width: h + 'px',
                height: w + 'px',
                position: 'fixed',
                transform: 'translate(-' + cha + 'px,' + cha + 'px) rotate(90deg)'
            }

clipboard.png

  • After the horizontal full, sliding around the events did not follow the change of direction

        //视频手势右滑动事件
        this.video.addEventListener('swiperight', function(e) {
            console.log('right');
            this.currentTime += 5;
        });
        //视频手势左滑动事件
        this.video.addEventListener('swipeleft', function(e) {
            console.log('left');
            this.currentTime -= 5;

        });

clipboard.png

TM This is very embarrassing, I do full-screen, the phone horizontally, also went down fast forward and rewind?

This time how to do it, do not square

Gesture slip events

We give a list of events registered video

    var events = {};
    
    //增加 或者删除事件
    pro.eve = function(ename, callback, isF) {
        if(callback && typeof(callback) == 'function') {
            isF && arguments.callee(ename);
            events[ename] = callback;
            this.video.addEventListener(ename, events[ename]);
            console.log('添加事件:' + ename);
            return;
        }
        var fun = events[ename] || function(){};
        this.video.removeEventListener(ename, fun);
        console.log('删除事件:' + ename);
        return fun;
    }

To the video event to add an agent to delete add an event, isF that is new this same event before the event is deleted, since adding an event with an anonymous function, it can not be deleted, so set up a proxy you can dynamically add events recorded in the event inside, easy to operate

Then we make progress on modifying the current playback and volume functions

    //跳转视频进度 单位 秒
    pro.setCurrentTime = function(t){
        this.video.currentTime += t;
    }
    //设置音量大小 单位 百分比 如 0.1
    pro.setVolume = function(v){
        this.video.volume+= v;
    }

Add slides up and down about the event through a proxy to video

        //视频手势右滑动事件
        this.eve('swiperight',function(){
            that.setCurrentTime(5);
        });
        
        //视频手势左滑动事件
        this.eve('swipeleft', function(e) {
            that.setCurrentTime(-5);
        });
        
        //视频手势上滑动事件
        this.eve('swipeup',function(){
            that.setVolume(0.2);
        });
        
        //视频手势下滑动事件
        this.eve('swipedown', function(e) {
            that.setCurrentTime(-0.2);
        });

ok, the four directions of the sliding events have been added later, but this is an event when the mini player mode, in full-screen playback, the four directions events did not change with video elements and the direction of change, which need to pass under the most the most stupid way to determine whether the event to trigger a full-screen

        //视频手势右滑动事件
        this.eve('swiperight',function(){
            if(that.isMax){
                return that.setVolume(0.2);
            }
            that.setCurrentTime(5);
        });
        
        //视频手势左滑动事件
        this.eve('swipeleft', function() {
            if(that.isMax){
                return that.setVolume(-0.2);
            }
            that.setCurrentTime(-5);
        });
        
        //视频手势上滑动事件
        this.eve('swipeup',function(){
            if(that.isMax){
                return that.setCurrentTime(-5);    
            }
            that.setVolume(0.2);
        });
        
        //视频手势下滑动事件
        this.eve('swipedown', function() {
            if(that.isMax){
                return that.setCurrentTime(5);    
            }
            that.setVolume(-0.2);
        });

How, although it looks a little stupid, but it is very practical

5+ fullscreen client solutions

Although the 5+ client, android can call the native way to play, but still far from satisfactory, we can look at a solution

During initialization, the recording time of mini pattern, full screen, the video by modifying the width of the screen height, the height of the video is a video width modify, reuse 5+ screen rotation, provided full screen, hide the status bar

0) to remove gesture event determining

因为现在是准备改变移动设备的方向,所以,手势方向会跟着设备方向改变

clipboard.png

1) removing css3 rotation and displacement


    //记录信息
    pro.initInfo = function() {
        var that = this;
        //在onload状态下,offsetHeight才会获取到正确的值
        window.onload = function() {
            that.miniInfo = { //mini状态时的样式
                zIndex: 1,
                width: that.video.offsetWidth + 'px',
                height: that.video.offsetHeight + 'px',
                position: that.vRoom.style.position
            }

            that.maxInfo = { //max状态时的样式
                zIndex: 99,
                width: '100%',
                height: that.sw + 'px',
                position: 'fixed'
            }

        }

    }

2) Set the full screen with 5+ and hide the status bar

    //全屏 mini 两种模式切换
    pro.switch = function() {
        var vR = this.vRoom;
        //获取需要转换的样式信息
        var info = this.isMax ? this.miniInfo : this.maxInfo;

        for(var i in info) {
            vR.style[i] = info[i];
        }
        this.isMax = !this.isMax;

        plus.navigator.setFullscreen(this.isMax);
        if(this.isMax) {
            //横屏
            plus.screen.lockOrientation("landscape-primary");
        } else {
            //竖屏
            plus.screen.lockOrientation("portrait-primary");
        }

    }

3) full screen mode, android end of the return key, the trigger to exit full screen

pro.initEvent = function() {
    //.......省略其他代码
    
    this.oback = $.back;
        //监听安卓返回键
        $.back = function() {
            if(that.isMax) {
                that.switch();
                return;
            }
            that.oback();
        }
}

Renderings
1.gif

5+ gravity sensing switch fullscreen

Hey, how can a little had automatically switch the screen anyway at the end of the player moving it?
In a small section of them told about how to manually toggle full screen, gravity sensor switch next horizontal screen, the need to use the API 5+ Accelerometer acceleration sensor

简单说:重力加速度感应可以想象成一个小球在坐标系中
三个方向上的加速度。永远以手机屏幕为准

What is the acceleration? The amount, is the physical book on

手机水平放置向上是y轴正向
向右是x轴正向,向外是z轴正向

What is xyz axes? The amount is on the high number of books

Oh, you put the phone portrait upright on the ground, you who walk uprightly went up, and now you're standing on your phone's screen, then you open the straight right hand, which is the x-axis, you are now looking at the front, which is the y-axis, z-axis is your head. Such talk does not understand, but does not really want to step on your phone, 23333

You can also choose to see additional explanation: Android-Sensor Development - determine the direction

  1. x, y-axis changes:

    When the phone screen is placed horizontally up: (x, y, z) = (0, 0, -9.81)
    When the top of the phone lift: y is reduced, and is negative
    when the bottom when lifting the phone: y increases, and is positive
    when the phone right lift: x is reduced, and a negative value
    when the phone left lift: x increases, and positive

  2. changes in the z-axis:
    the phone screen is upward horizontally, z = -9.81
    when the phone screen vertically, z = 0
    when the phone is placed horizontally down the screen, z = 9.81

  3. Vertical screen switching condition
    y <= - 5, the switching of the vertical
    x <= - 5, the transducer is a lateral

ok, we added two methods for opening and closing device monitoring

    //开启方向感应
    pro.startWatchAcc = function(){
        var that = this;
        this.watchAccFun = plus.accelerometer.watchAcceleration(function(a) {
                if(that.getIsMax()){
                    //当前为全屏状态
                    //判断是否满足竖屏Mini状态
                    a.yAxis>=5 && that.setIsMax(false);
                }else{
                    //当前为Mini状态
                    //判断是否满足全屏Max状态
                    Math.abs(a.xAxis) >=5 && that.setIsMax(true); 
                }
            }, function(e) {
                //出错了大不了 不自动旋转呗  让它手动 切换
                console.log("Acceleration error: " + e.message);
                that.clearWatchAcc();
            },{
                frequency:1200
            });
    }
    //关闭方向感应
    pro.clearWatchAcc = function(){
        this.watchAccFun && plus.accelerometer.clearWatch(this.watchAccFun);
    }

Then turned on by default during initialization direction monitoring

    var bvd = function(dom) {
        var that = this;
        $.ready(function() {
            //...
        })

        $.plusReady(function() {
            that.startWatchAcc();
        })

    }

Then changed to horizontal full, two-way cross-screen

clipboard.png

Take a look at the real machine debugging

ziong.gif

Hey, we add a lock to give full-screen playback button, gravity sensor so that the device does not monitor nor pause event response Click to play video

Do a lock button

clipboard.png

Of course, lock pictures, address also changed with base64, at best dynamically generated label js

clipboard.png

Set its basic style, right, up and down vertically centered, hidden by default

        .lock {
            padding: .3rem;
            width: 3rem;
            height: 3rem;
            position: absolute;
            right: .5rem;
            top: 50%;
            transform: translateY(-50%);
            -webkit-transform: translateY(-50%);
            visibility: hidden;
        }

clipboard.png

Well, let's sort out the logic,

1) by default when playing mini, lock hide
2) full-screen playback, lock the display, but will follow the control bar off to the right in the 4S
3) full screen to pause, followed lock control are always displayed
4) Click when lock is locked, Tip locked, hide the control bar immediately, hidden right inside lock4s, replace the click event video display lock icon, android return key event without any change, close monitoring of gravity
5) when you click lock unlocked, unlocked prompt, android return key instead switched to the mini state, open gravity monitoring

I rub, it is actually quite depressing, mainly logic processing more painful

0) Add a moving animation right after 3s delay within 1s after executing animation

@keyframes lockhide {0% {transform: translate(0%,-50%);}100% {transform: translate(120%,-50%);}}

webkit-keyframes lockhide {0% {transform: translate(0%,-50%);}100% {transform: translate(120%,-50%);}}

.lockhidden {
    animation: lockhide 1s 3s linear;
    -webkit-animation: lockhide 1s 3s linear;
    animation-fill-mode:forwards;
    -webkit-animation-fill-mode: forwards;
}

1) full screen display lock

    pro.switch = function() {
        //...
        //全屏时 显示锁定 图标
        this.vlock.style.visibility = this.isMax ? 'visible' : 'hidden';

    }

2) full-screen playback, lock the display, but will follow the control bar off to the right in the 4s
hidden animations we add lock when playing,

clipboard.png

3) full-screen pause, lock controls are always displayed followed

clipboard.png

4) Click the lock to lock, locked prompt, immediate control bar hidden, hidden right inside lock4s, replace the click event video display lock icon, android return key event without any change, close monitoring of gravity
5) Click the lock unlocked, Tip unlocked, android return key instead switch to mini state, open the gravity monitoring

    //锁定屏幕
    pro.lockScreen = function() {
        $.toast('锁定屏幕');
        var that = this;
        //更换video点击事件为 显示 lock图标,并保存 video之前的事件 
        this.videoTapFn = this.eve('tap', function() {
            that.lockT = setTimeout(function(){
                that.vlock.classList.add('lockhidden');
            },500);
                //重新开始播放样式
            that.vlock.classList.remove('lockhidden');
            that.vlock.style.visibility = 'visible';
        }, true);
        //隐藏控制条
        this.vC.style.visibility = 'hidden';
        //给Lock图标增加 隐藏样式类
        this.vlock.classList.add('lockhidden');
        //锁定屏幕时,不监控重力感应
        this.clearWatchAcc();
        //标识当前更改的Lock状态
        this.isLock = true;

    }

    //解锁屏幕
    pro.unlockScreen = function() {
        $.toast('解锁屏幕');
        //替换回video之前的点击事件
        this.eve('tap', this.videoTapFn, true);
        //给Lock图标清楚 隐藏样式类
        this.vlock.classList.remove('lockhidden');
        //不锁定屏幕时,监控重力感应
        this.startWatchAcc();
        //标识当前更改的Lock状态
        this.isLock = false;
    }

666) Finally, to our dear lock icon increase a touch event, and the event android return key changes

        //全屏 时 锁定点击事件
        this.vlock.addEventListener('tap', function() {
            if(that.isLock) {
                that.unlockScreen();
                return;
            }
            that.lockScreen();
        });

        this.oback = $.back;
        //监听安卓返回键
        $.back = function(){
            if(that.isMax){
                if(!that.isLock){
                    //全屏状态下 按下返回键 时,1s内不监控重力,防止返回Mini状态时和重力感应并发事件
                    setTimeout(function(){
                        that.startWatchAcc();
                    },1000);
                    that.clearWatchAcc();
                    that.switch();
                }
                return;
            }
            that.oback();
        }
    }

All right! This article 5+ fullscreen demo source address

Write blog is not easy, but that share the mood is very good, is it not another review and progress?

Thank you.

This article Related articles: H5 create their own video player column

Guess you like

Origin www.cnblogs.com/10manongit/p/12616555.html