当前位置:网站首页>H5 makes its own video player (JS Part 2)

H5 makes its own video player (JS Part 2)

2020-11-06 01:17:00 :::::::

review

Forget it. No review

Start directly , open JS1 Written in bvd.js

Play the video

  1. Play button hidden
  2. The video starts playing When you click the play button , The play button will be hidden , Play the video , This is not hard to , stay JS1 We've already achieved . But let's change our thinking , Add a click to the video tap event , Make the video play , Then trigger the playback event , So that the play button is hidden pro.initEvent = function(){ var that = this; // Add events to the play button image this.vimg.addEventListener('tap',function(){ that.video.play(); }) // Video Click to pause or play events this.video.addEventListener('tap',function(){ if(this.paused || this.ended) { // When you pause, click to play if(this.ended) {// If it's over , It starts all over again this.currentTime = 0; } this.play(); } else { // Click to pause while playing this.pause(); } }) // Video playback Events this.video.addEventListener('play',function(){ that.vimg.style.display = 'none'; }) // Get metadata this.video.addEventListener('loadedmetadata',function(){ that.vC.querySelector('.duration').innerHTML = stom(this.duration); }); }
  3. The lower control bar is gradually hidden Hiding is not the difficulty , The important thing is to gradually hide , Here we have several solutions :
    1. Timer
    2. css3 Animation frames

Here we are 2 To use in combination

First, let's define a set of animations

@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 3.5 Seconds 1=>0,ease-in Namely From slow to fast Over effect of . Do you understand css Animation can ask Du Niang And then we give the video, when it starts playing events, to Control bar add to vhidden Style class

// Video playback Events 
this.video.addEventListener('play',function(){
    that.vC.classList.add('vhidden');
})

The test results , Sure enough 3.5s Inside , Control bar Slowly transparent , The problem is 3.5s after , Transparency is back to 1, Here I'll explain , Because the animation frame is rebound by default , We can add a 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 attribute animation-fill-mode Used to define what an element looks like after the animation .

animation-fill-mode The default value of is none, That is, after the end of the animation, no changes will be made , If you put animation-fill-mode Change to forwards After the animation, the style of the element will become the style specified by the last key frame of the animation .

After adding this pattern , Sure enough 3.5s after , Animation doesn't bounce back anymore , But pay attention here , The control bar is not no longer there, but transparent , If we have a click time to write the control bar , Then click on the control bar , Or trigger events , So , We can also write a paragraph setTimeout Come on , Let the control bar 3.5s Hide behind , You can make your own choice

// Video playback Events 
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 is the animation process 3.5s, However js Yes 3.4s After execution , It's just not written here animation-fill-mode:forwards In the case of insurance

It's playing

Hey , The video can be played ! So now we should think about what we have to do on the air ?

1. The control bar, the progress bar, grows slowly

We need to add a piece to the video timeupdate The event when the audio and video playback position changes

Let's start with the video metadata event , Take down the length of the video

// Get metadata 
this.video.addEventListener('loadedmetadata',function(){
    that.vDuration = this.duration;
    that.vC.querySelector('.duration').innerHTML = stom(that.vDuration);
});

Then calculate the ratio from the video playback progress update event , Set the width of the progress bar

// Events in video playback 
this.video.addEventListener('timeupdate', function() {
    var currentPos = this.currentTime;// Gets the current playback location 
    // Update progress bar 
    var percentage = 100 * currentPos / that.vDuration; 
    // Set width 
    that.vC.querySelector('.timeBar').style.width = percentage + '%';
});

We can see that our progress bar is getting bigger and bigger .

2. Current playback time changes

meanwhile , Our current playback time is also displayed in timeupdate Set in the event

// Events in video playback 
this.video.addEventListener('timeupdate', function() {
    var currentPos = this.currentTime;// Gets the current playback location 
    // Update progress bar 
    var percentage = 100 * currentPos / that.vDuration; 
    that.vC.querySelector('.timeBar').style.width = percentage + '%';
    // Update current playback time 
    that.vC.querySelector('.current').innerHTML = stom(currentPos);
});

Pause or stop it

When we click on the video , If it's a pause , Let's start playing , And trigger the playback event , On the contrary, the video is playing , Click on the video and it will pause , And trigger a pause event .

0. Time frame

La la la , Pause play ,timeupdate Naturally, events don't trigger , The current progress and time will not change .

1. The play button shows

During the pause , Just show the button

// Pause or stop it 
this.video.addEventListener('pause',function(){
    that.vimg.style.display = 'block';
});

2. The lower control bar shows

The control bar shows , Just get rid of that vhidden Just the style class

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

It seems that there is nothing wrong with this writing , however , If you've written before when you've hidden the control bar setTimeout Words , It's time to get rid of it .

// Pause or stop it 
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, fast backward

How can a small video player with its mouth in its mouth be less, can it be advanced, retractable and flexible ?

Come on , Let's start with video Add left slide right slide event

// Video gesture right slide event 
this.video.addEventListener('swiperight',function(e){
    this.currentTime += 5;
});
// Video gesture left slide event 
this.video.addEventListener('swipeleft',function(e){
    this.currentTime -= 5;
});

Maybe debugging on the computer will change the progress directly 0, At first, I was wondering , It turns out that on the mobile phone webview It seems to be feasible .

About Drag the progress bar to change the video progress I'm not going to write , Because I haven't written yet .

Play full screen

Maybe you will pay more attention to this :

ios End : Remove video label webkit-playsinline Attribute is enough , because ios Yes h5 Of video Tag support is still quite good

// Call native mode   Play full screen 
pro.nativeMax = function(){
    if(!window.plus){
        // Not html5+ Environmental Science 
        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);
    }
}

stay initEvent Add click on Full screen event

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

It's a little chicken ribs , You can't have a little generic ?

It's true that I've been thinking about this all night , Decided to bring some more dry goods .

Give me a state first , The default is mini Play

var bvd = function(dom) {
    var that = this;
    $.ready(function() {
        // Get video elements 
        that.video = document.querySelector(dom || 'video');
        // Get video parent element 
        that.vRoom = that.video.parentNode;
        // Element initialization 
        that.initEm();
        // Event initialization 
        that.initEvent();
        // Record information 
        that.initInfo();
        // Current playback mode  false  by  mini Play 
        that.isMax = false;
    })
}

// Record information 
pro.initInfo = function() {
    var that = this;
    // stay onload State, ,offsetHeight To get the correct value 
    window.onload = function(){
        that.miniInfo = {//mini The pattern of state 
            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 The pattern of state 
            width: h + 'px',
            height: w + 'px',
            position: 'fixed',
            transform: 'translate(-' + cha + 'px,' + cha + 'px) rotate(90deg)'
        }
    }
    
    
}

// Full screen  mini  Switch between the two modes 
pro.switch = function() {
    var vR = this.vRoom;
    // Get the style information that needs to be transformed 
    var info = this.isMax ? this.miniInfo : this.maxInfo;
    for(var i in info) {
        vR.style[i] = info[i];
    }
    this.isMax = !this.isMax;
}

// Full screen button 
this.vC.querySelector('.fill').addEventListener('tap', function() {
    //that.nativeMax();
    that.switch();
});

Take a look , Take a look at it

It looks like it feels good , utilize css3 The displacement and rotation of , Let the video full screen in front of the screen , But the problem comes with

  • Play button as well as Control bar In full screen It seems to be hiding , It's actually video The tag is over the parent element , We adjust accordingly

css

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

js max In the configuration , Set up zIndex value

            that.maxInfo = {//max The pattern of state 
                zIndex:99,
                width: h + 'px',
                height: w + 'px',
                position: 'fixed',
                transform: 'translate(-' + cha + 'px,' + cha + 'px) rotate(90deg)'
            }
  • Horizontal full screen , Left and right slip events do not change with direction
        // Video gesture right slide event 
        this.video.addEventListener('swiperight', function(e) {
            console.log('right');
            this.currentTime += 5;
        });
        // Video gesture left slide event 
        this.video.addEventListener('swipeleft', function(e) {
            console.log('left');
            this.currentTime -= 5;

        });

this TM It's embarrassing , Can't I have a full screen , Mobile phone horizontal , Go up and down, fast forward, fast backward ?

What do you do then , Don't party

Gesture slide Events

Let's give it first video Register an event list

    var events = {};
    
    // increase   Or delete the event 
    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(' Add event :' + ename);
            return;
        }
        var fun = events[ename] || function(){};
        this.video.removeEventListener(ename, fun);
        console.log(' Delete event :' + ename);
        return fun;
    }

to video Event add a proxy to delete the add event ,isF Whether to delete the same event before adding this event , Because if you use anonymous functions to add events , It can't be deleted , In this way, a proxy can be set up to record dynamically added events in events Inside , Easy to operate

At this time, we add the function of modifying the current playback progress and volume

    // Jump to video progress   Company   second 
    pro.setCurrentTime = function(t){
        this.video.currentTime += t;
    }
    // Set the volume   Company   percentage   Such as  0.1
    pro.setVolume = function(v){
        this.video.volume+= v;
    }

Then through the agency to video Add events that slide left and right up and down

        // Video gesture right slide event 
        this.eve('swiperight',function(){
            that.setCurrentTime(5);
        });
        
        // Video gesture left slide event 
        this.eve('swipeleft', function(e) {
            that.setCurrentTime(-5);
        });
        
        // Slide events on video gestures 
        this.eve('swipeup',function(){
            that.setVolume(0.2);
        });
        
        // Video gesture slide event 
        this.eve('swipedown', function(e) {
            that.setCurrentTime(-0.2);
        });

ok, Sliding events in four directions have been added , But this is mini Mode playback Events , In full screen , Events in four directions did not follow video The direction of the elements changes , This requires the most stupid way to determine whether the full screen triggers the event

        // Video gesture right slide event 
        this.eve('swiperight',function(){
            if(that.isMax){
                return that.setVolume(0.2);
            }
            that.setCurrentTime(5);
        });
        
        // Video gesture left slide event 
        this.eve('swipeleft', function() {
            if(that.isMax){
                return that.setVolume(-0.2);
            }
            that.setCurrentTime(-5);
        });
        
        // Slide events on video gestures 
        this.eve('swipeup',function(){
            if(that.isMax){
                return that.setCurrentTime(-5);    
            }
            that.setVolume(0.2);
        });
        
        // Video gesture slide event 
        this.eve('swipedown', function() {
            if(that.isMax){
                return that.setCurrentTime(5);    
            }
            that.setVolume(-0.2);
        });

What about? , Although it looks a little bit stupid, But it's very practical

5+ Client full screen solution

Although in 5+ client ,android You can call the native way to play , But it's not good enough , We can look at another set of solutions

On initialization , Record mini Style of time , In full screen , By modifying the video width to the screen height , Change video height to video width , recycling 5+ The screen rotates , Set full screen , hide the status bar

0) Remove gesture event judgment

 Because it's time to change the direction of mobile devices , therefore , The direction of the gesture changes with the direction of the device 

1) Remove css3 Rotation and displacement

    // Record information 
    pro.initInfo = function() {
        var that = this;
        // stay onload State, ,offsetHeight To get the correct value 
        window.onload = function() {
            that.miniInfo = { //mini The pattern of state 
                zIndex: 1,
                width: that.video.offsetWidth + 'px',
                height: that.video.offsetHeight + 'px',
                position: that.vRoom.style.position
            }

            that.maxInfo = { //max The pattern of state 
                zIndex: 99,
                width: '100%',
                height: that.sw + 'px',
                position: 'fixed'
            }

        }

    }

2) This use 5+ Set full screen and hide status bar

    // Full screen  mini  Switch between the two modes 
    pro.switch = function() {
        var vR = this.vRoom;
        // Get the style information that needs to be transformed 
        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) {
            // Horizontal screen 
            plus.screen.lockOrientation("landscape-primary");
        } else {
            // Vertical screen 
            plus.screen.lockOrientation("portrait-primary");
        }

    }

3) In full screen mode ,android End return key , Trigger to exit full screen

pro.initEvent = function() {
    //....... Omit other code 
    
    this.oback = $.back;
        // Listen to Android return key 
        $.back = function() {
            if(that.isMax) {
                that.switch();
                return;
            }
            that.oback();
        }
}

design sketch

5+ Gravity switch full screen

Hey , How can a player be less mobile Automatic switch Horizontal and vertical screens ? How to manually switch full screen , Next, gravity sensor switches the horizontal screen , Need to use 5+ Of API Accelerometer Acceleration sensing

 In short : Gravitational acceleration can be thought of as a ball in a coordinate system 
 Acceleration in three directions . Always follow the screen of your mobile phone 

What is acceleration ? forehead , It's from the physics book

 The mobile phone is placed horizontally upward y Positive axis 
 To the right is x Positive axis , Outward is z Positive axis 

What is xyz Axis ? forehead , It's from high mathematics books

Oh dear , You put your mobile phone upright on the ground , You just walk up there , Now you're standing on the screen of your phone , And then your right hand opens and straightens , This is it. x Axis , You're looking ahead , This is it. y Axis , It's on top of your head z Axis . That's clear. No , But it's not really about stepping on your cell phone ,23333

You can also choose to view other explanations :Android- Sensor development - Direction judgment

  1. x,y Axis change : When the mobile phone screen is placed horizontally upward : (x,y,z) = (0, 0, -9.81) When the top of the phone is raised : y Reduce , And it's negative When the bottom of the phone is raised : y increase , And it's positive When the right side of the phone is raised : x Reduce , And it's negative When the left side of the phone is raised : x increase , And it's positive
  2. z Change of axis : When the mobile phone screen is placed horizontally upward ,z= -9.81 When the phone screen is placed vertically , z= 0 When the mobile phone screen is placed horizontally down ,z= 9.81
  3. Screen vertical and horizontal switching conditions y<=-5 when , Switch to vertical x<=-5 when , Change to horizontal

ok, We added 2 A way , Used to turn on and off device monitoring

    // Turn on direction sensing 
    pro.startWatchAcc = function(){
        var that = this;
        this.watchAccFun = plus.accelerometer.watchAcceleration(function(a) {
                if(that.getIsMax()){
                    // The current state is full screen 
                    // Determine whether the vertical screen is satisfied Mini state 
                    a.yAxis>=5 && that.setIsMax(false);
                }else{
                    // At present, it is Mini state 
                    // Judge whether it satisfies the full screen Max state 
                    Math.abs(a.xAxis) >=5 && that.setIsMax(true); 
                }
            }, function(e) {
                // It's a big deal to make a mistake   It doesn't rotate automatically    Let it be manual   Switch 
                console.log("Acceleration error: " + e.message);
                that.clearWatchAcc();
            },{
                frequency:1200
            });
    }
    // Turn off directional sensing 
    pro.clearWatchAcc = function(){
        this.watchAccFun && plus.accelerometer.clearWatch(this.watchAccFun);
    }

Then, the direction monitoring is turned on by default during initialization

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

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

    }

Then change the horizontal full screen to , Can be two-way horizontal screen

Real machine debugging to see

Hey , Let's add a lock button for full screen playback , Let the device not monitor Gravity induction , Also does not respond to the video click play pause event

Make a lock button first

Of course , Lock picture , The address was changed to use base64, It's better to use js Dynamically generate tags

Set its basic style , Keep right , Vertical center up and down , Hide by default

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

good , Let's sort out the logic ,

1) Default in mini When the play ,lock hide 2) When playing full screen ,lock Show , But it also follows the control bar stay 4s Hide inside right 3) When full screen pauses ,lock With the control bar Always show 4) Click on lock When locked , The prompt is locked , The control bar is hidden immediately ,lock4s Hide inside right , Video click events are replaced by display lock Icon ,android The return key event is changed to do nothing , Turn off gravity monitoring 5) Click on lock When the unlock , The prompt is unlocked ,android The return key is changed to Switch to a mini state , Turn on gravity monitoring

I wipe , In fact, it's quite depressing to do it , The main reason is that logic processing is painful

0) Add an animation that moves right ,3s After the delay 1s Inside After executing the 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) Show... In full screen lock

    pro.switch = function() {
        //...
        // In full screen   According to lock   Icon 
        this.vlock.style.visibility = this.isMax ? 'visible' : 'hidden';

    }

2) When playing full screen ,lock Show , But it also follows the control bar stay 4s Hide inside right We add lock The hidden animation of ,

3) When full screen pauses ,lock With the control bar Always show

4) Click on lock When locked , The prompt is locked , The control bar is hidden immediately ,lock4s Hide inside right , Video click events are replaced by display lock Icon ,android The return key event is changed to do nothing , Turn off gravity monitoring 5) Click on lock When the unlock , The prompt is unlocked ,android The return key is changed to Switch to a mini state , Turn on gravity monitoring

    // Lock screen 
    pro.lockScreen = function() {
        $.toast(' Lock screen ');
        var that = this;
        // Replace video Click the event as   Show  lock Icon , And save  video Previous events  
        this.videoTapFn = this.eve('tap', function() {
            that.lockT = setTimeout(function(){
                that.vlock.classList.add('lockhidden');
            },500);
                // Restart playing styles 
            that.vlock.classList.remove('lockhidden');
            that.vlock.style.visibility = 'visible';
        }, true);
        // Hide the control bar 
        this.vC.style.visibility = 'hidden';
        // to Lock Icon added   Hidden style class 
        this.vlock.classList.add('lockhidden');
        // When you lock the screen , Don't monitor gravity sensing 
        this.clearWatchAcc();
        // Identifies the currently changed Lock state 
        this.isLock = true;

    }

    // Unlock screen 
    pro.unlockScreen = function() {
        $.toast(' Unlock screen ');
        // Replace with video Previous click events 
        this.eve('tap', this.videoTapFn, true);
        // to Lock The icon is clear   Hidden style class 
        this.vlock.classList.remove('lockhidden');
        // When you don't lock the screen , Monitoring gravity sensing 
        this.startWatchAcc();
        // Identifies the currently changed Lock state 
        this.isLock = false;
    }

666) Finally, to our dear lock Add a touch event to the icon , as well as android Return key event change

        // Full screen   when   Lock click events 
        this.vlock.addEventListener('tap', function() {
            if(that.isLock) {
                that.unlockScreen();
                return;
            }
            that.lockScreen();
        });

        this.oback = $.back;
        // Listen to Android return key 
        $.back = function(){
            if(that.isMax){
                if(!that.isLock){
                    // In full screen mode   Press the back key   when ,1s It doesn't monitor gravity , Prevent return Mini State time and gravimetry are concurrent events 
                    setTimeout(function(){
                        that.startWatchAcc();
                    },1000);
                    that.clearWatchAcc();
                    that.switch();
                }
                return;
            }
            that.oback();
        }
    }

Okay ! this paper 5+ Full screen demo Source code address

It's not easy to blog , But that kind of sharing mood is very good , It's another kind of review and progress ?

Thank you .

This article related article :H5 Build your own video player special column

Participation of this paper Tencent cloud media sharing plan , You are welcome to join us , share .

版权声明
本文为[:::::::]所创,转载请带上原文链接,感谢