综合编程

Create Custom Video Player Controls with CanJS

微信扫一扫,分享到朋友圈

Create Custom Video Player Controls with CanJS
0

In this guide, you will learn how to create a custom video player using the
element and CanJS. The

custom video player will:


The final player looks like:

The following sections are broken down into the following parts:

  • The problem
    — A description of what the section is trying to accomplish.
  • What you need to know
    — Browser or CanJS APIs that are useful for solving the problem.
  • The solution
    — The solution to the problem.

Setup

START THIS TUTORIAL BY Forking THE FOLLOWING CodePen:

Click the Edit in CodePen
button. The CodePen will open in a new window. Click the Fork
button.

This CodePen:

  • Creates a
    element that loads a video. Right click and select “Show controls” to see the video’s controls
    .
  • Loads CanJS’s custom element library: Component.

The problem

In this section, we will:

  • Create a custom
    element that takes a src
    attribute and creates a
    element

    within itself. We should be able to create the video like:

    
    
  • The embedded
    element should have the native controls enabled.

When complete, the result will look exactly the same as the player when you started. The

only difference is that we will be using a custom
element in the HTML

tab instead of the native
element.

What you need to know

To set up a basic CanJS application (or widget), you define a custom element in JavaScript and

use the custom element in your page’s HTML
.

To define a custom element, extend Component with a tag

Component.extend({
    tag: "video-player"
})

Then you can use this tag in your HTML page:


But this doesn’t do anything … yet. Components add their own HTML through their Component.extend({
tag: “video-player”,
view: `

I am a player!

`
});
A component’s ViewModel. For example, we can make a
display "http://bit.ly/can-tom-n-jerry"
by defining a src
property on the ViewModel

and using it in the Component.extend({ tag: “video-player”, view: ` `, ViewModel: { src: {type: “string”, default: “http://bit.ly/can-tom-n-jerry”} } });

But we want the
to take a src
attribute value itself and use that for the


’s src
. For example, if

we wanted the video to play "http://dl3.webmfiles.org/big-buck-bunny_trailer.webm"
instead of "http://bit.ly/can-tom-n-jerry"
, we would:

  1. Update
    to pass "http://dl3.webmfiles.org/big-buck-bunny_trailer.webm"
    with toChild:raw:

    
    
  2. Update the ViewModel to define a src
    property like:

    Component.extend({
        tag: "video-player",
        view: `
            
        `,
        ViewModel: {
            src: "string"
        }
    });

Finally, to have a
element show the native
controls, add a controls

attribute like:

The solution

Update the JS
tab to:

import {Component} from "//unpkg.com/[email protected]/core.mjs";

Component.extend({                        //
    tag: "video-player",                  //
    view: `                              {{!}}
                                 {{!}}
    `,                                    //
    ViewModel: {                          //
        src: "string",                    //
    }                                     //
});                                       //

Update the HTML
to:

   

Make play / pause button change as video is played and paused

The problem

When the video is played or paused using the native controls, we want to change the content of a

What you need to know

  • To change the HTML content of the page, use {{#if(expression)}} and {{else}} like:

  • The ViewModel. To create a boolean
    value in the ViewModel do:

    ViewModel: {
        // ...
        playing: "boolean",
    }
  • Methods can be used to change the ViewModel. The following might create methods that change the playing
    value:

    ViewModel: {
        // ...
        play() {
            this.playing = true;
        },
        pause() {
            this.playing = false;
        },
    }
  • You can listen to events on the DOM with on:event. For example, the following might

    listen to a click on a


    and call doSomething()
    :


    elements have a variety of useful events, including play and

    pause events that are emitted when the video is played or paused.

The solution

Update the JavaScript
tab to:

import {Component} from "//unpkg.com/[email protected]/core.mjs";

Component.extend({
    tag: "video-player",
    view: `
        
        
{{!}} {{!}}
{{!}} `, ViewModel: { src: "string", playing: "boolean", // play() { // this.playing = true; // }, // pause() { // this.playing = false; // }, // } });

Make clicking the play/pause button play or pause the video

The problem

When the play/pause

`, ViewModel: { src: "string", playing: "boolean", play() { this.playing = true; }, pause() { this.playing = false; }, togglePlay() { // this.playing = !this.playing; // }, // connectedCallback(element) { // this.listenTo("playing", function(event, isPlaying) { // if (isPlaying) { // element.querySelector("video").play(); // } else { // element.querySelector("video").pause(); // } // }); // } // } });

Show current time and duration

The problem

Show the current time and duration of the video element. The time and duration should be

formatted like: mm:SS
. They should be presented within two spans like:


1:22
2:45

What you need to know

  1. Methods can be used to format values in can-stache. For example, you can uppercase values like this:

    {{upper(value)}}

    With a method like:

    ViewModel: {
        // ...
        upper(value) {
            return value.toString().toUpperCase();
        }
    }

    The following can be used to format time:

    formatTime(time) {
        if (time === null || time === undefined) {
            return "--";
        }
        const minutes = Math.floor(time / 60);
        let seconds = Math.floor(time - minutes * 60);
        if (seconds < 10) {
            seconds = "0" + seconds;
        }
        return minutes + ":" + seconds;
    }
  2. Time is given as a number. Use the following to create a number property on

    ViewModel: {
        // ...
        duration: "number",
        currentTime: "number"
    }

  3. elements emit a loadmetadata event when they know how long

    the video is. They also emit a timeupdate event when the video’s current play position

    changes.

    videoElement.duration
    videoElement.currentTime
    
  4. You can get the element in an stache on:event
    binding with scope.element like:

The solution

Update the JavaScript
tab to:

import {Component} from "//unpkg.com/[email protected]/core.mjs";

Component.extend({
    tag: "video-player",
    view: `
        
        
{{formatTime(currentTime)}} / {{!}} {{formatTime(duration)}} {{!}}
`, ViewModel: { src: "string", playing: "boolean", duration: "number", // currentTime: "number", // updateTimes(videoElement) { // this.currentTime = videoElement.currentTime || 0; // this.duration = videoElement.duration; // }, // formatTime(time) { // if (time === null || time === undefined) { // return "--"; // } // const minutes = Math.floor(time / 60); // let seconds = Math.floor(time - minutes * 60); // if (seconds < 10) { // seconds = "0" + seconds; // } // return minutes + ":" + seconds; // }, // play() { this.playing = true; }, pause() { this.playing = false; }, togglePlay() { this.playing = !this.playing; }, connectedCallback(element) { this.listenTo("playing", function(event, isPlaying) { if (isPlaying) { element.querySelector("video").play(); } else { element.querySelector("video").pause(); } }); } } });

Make range show position slider at current time

The problem

Create a
element that changes its position as

the video playing position changes.

The
element should be after the {{formatTime(currentTime)}} /

What you need to know

  • The range input can have an initial value, max value, and step size

    
    
  • The range will have values from 0 to 1. We will need to translate the currentTime to

    ViewModel: {
        // ...
        get percentComplete() {
            return this.currentTime / this.duration;
        },
    }
  • Use key:from to update a value from a ViewModel property like:

    
    

The solution

Update the JavaScript
tab to:

import {Component} from "//unpkg.com/[email protected]/core.mjs";

Component.extend({
    tag: "video-player",
    view: `
        
        
{{!}} {{formatTime(currentTime)}} / {{formatTime(duration)}}
`, ViewModel: { src: "string", playing: "boolean", duration: "number", currentTime: "number", get percentComplete() { // return this.currentTime / this.duration; // }, // updateTimes(videoElement) { this.currentTime = videoElement.currentTime || 0; this.duration = videoElement.duration; }, formatTime(time) { if (time === null || time === undefined) { return "--"; } const minutes = Math.floor(time / 60); let seconds = Math.floor(time - minutes * 60); if (seconds < 10) { seconds = "0" + seconds; } return minutes + ":" + seconds; }, play() { this.playing = true; }, pause() { this.playing = false; }, togglePlay() { this.playing = !this.playing; }, connectedCallback(element) { this.listenTo("playing", function(event, isPlaying) { if (isPlaying) { element.querySelector("video").play(); } else { element.querySelector("video").pause(); } }); } } });

Make sliding the range update the current time

The problem

In this section we will:

  • Remove the native controls from the video player. We don’t need them anymore!
  • Make it so when a user moves the range slider, the video position updates.

What you need to know

Similar to when we made the play/pause button play or pause the video, we will want to update the

currentTime
property and then listen to when currentTime
changes and update the

element’s currentTime
as a side-effect
.

This time, we need to translate the sliders values between 0 and 1 to currentTime

values. We can do this by creating a percentComplete
setter that updates currentTime
like:

ViewModel: {
    // ...
    get percentComplete() {
        return this.currentTime / this.duration;
    },
    set percentComplete(newVal) {
        this.currentTime = newVal * this.duration;
    },
    // ...
}

Use key:bind to two-way bind a value to a ViewModel property:


The solution

Update the JavaScript
tab to:

import {Component} from "//unpkg.com/[email protected]/core.mjs";

Component.extend({
    tag: "video-player",
    view: `
        
        
{{!}} {{formatTime(currentTime)}} / {{formatTime(duration)}}
`, ViewModel: { src: "string", playing: "boolean", duration: "number", currentTime: "number", get percentComplete() { return this.currentTime / this.duration; }, set percentComplete(newVal) { // this.currentTime = newVal * this.duration; // }, // updateTimes(videoElement) { this.currentTime = videoElement.currentTime || 0; this.duration = videoElement.duration; }, formatTime(time) { if (time === null || time === undefined) { return "--"; } const minutes = Math.floor(time / 60); let seconds = Math.floor(time - minutes * 60); if (seconds < 10) { seconds = "0" + seconds; } return minutes + ":" + seconds; }, play() { this.playing = true; }, pause() { this.playing = false; }, togglePlay() { this.playing = !this.playing; }, connectedCallback(element) { this.listenTo("playing", function(event, isPlaying) { if (isPlaying) { element.querySelector("video").play(); } else { element.querySelector("video").pause(); } }); this.listenTo("currentTime", function(event, currentTime) { // const videoElement = element.querySelector("video"); // if (currentTime !== videoElement.currentTime) { // videoElement.currentTime = currentTime; // } // }); // } } });

Result

When finished, you should see something like the following JS Bin:

The post Create Custom Video Player Controls with CanJS appeared first on David Walsh Blog.

阅读原文...


微信扫一扫,分享到朋友圈

Create Custom Video Player Controls with CanJS
0

JSFeeds

总结:工业互联网安全受到威胁主要有三点原因

上一篇

What media agency woes say about marketers' shifting priorities

下一篇

评论已经被关闭。

插入图片

热门分类

往期推荐

Create Custom Video Player Controls with CanJS

长按储存图像,分享给朋友