HTML5 音楽プレーヤーの例を実装する

零下一度
リリース: 2017-07-23 13:28:16
オリジナル
6144 人が閲覧しました

技術的なポイント: ES6+Webpack+HTML5 Audio+Sass

ここでは、H5 音楽プレーヤーをゼロから実装する方法を段階的に学びます。

まず、最終的な実装を見てみましょう: デモリンク

それから本題に入りましょう:

  1. 音楽プレーヤーになるには、Web 上でオーディオが再生される方法をよく理解する必要があります、HTML5のaudioタグがよく使われます
    audioタグについては、たくさんの属性、メソッド、イベントがありますので、ここで概要を説明します。

    属性:
    src: 必須、オーディオ ソース;
    controls: 共通、設定後にブラウザのデフォルトのオーディオ コントロール パネルが表示され、設定されていない場合、オーディオ タグはデフォルトで非表示になります。設定後に自動的に再生されます (モバイル端末ではサポートされません) );
    loop: 共通、設定後にオーディオがループで再生されます。
    volume: レア、設定されます。または、オーディオ サイズを返します。値は 0 ~ 1 の浮動小数点数です (モバイル デバイスではサポートされていません)。
    muted: レア、ミュート状態に戻ります。現在の再生時間を設定または返します。
    paused: rare、一時停止するかどうか、現在の再生状態に戻ります。
    buffered: rare、バッファリングされた期間情報、つまり読み込みの進行状況を含む TimeRanges オブジェクト。このオブジェクトには属性 length が含まれており、現在バッファリングされているオーディオ セグメントの数を示す 0 から始まる数値を返します。また、start と end の 2 つのメソッドも含まれており、それぞれパラメータ、つまり、どのセグメントを渡す必要があるかを示します。オーディオは0から読み込まれています。 start はセグメントの開始時間を返し、end はセグメントの終了時間を返します。例: 0 を渡します。最初の段落の開始は 0、終了時間は 17、単位は秒です。ここでは
    属性が導入されていますが、playbackRate などのあまり使用されない属性がある可能性があります。動画再生時に使用する場合がありますので、説明は省略します。

    メソッド:
    play(): オーディオの再生を開始します;
    pause(): オーディオの再生を一時停止します;

    イベント:
    canplay: 現在のオーディオの再生を開始できます (バッファーされたオーディオの一部のみがロードされます。すべてがロードされるわけではありません)。
    canplaythrough : 一時停止せずに再生できます (つまり、すべてのオーディオがロードされます)。開始;
    progress: オーディオのダウンロード イベントトリガープロセス中に、オーディオのバッファリングされた属性にアクセスすることで、読み込みの進行状況を取得できます。 : オーディオのジャンプが完了したとき、つまり currentTime が変更されたときにトリガーされます。
    timeupdate: オーディオの再生中にトリガーされ、currentTime 属性が同期的に更新されます。
    イベントはここで紹介されていますが、あまり使用されないイベントもあるかもしれません。まだ説明されるでしょう。

    最後に、読み込みの開始から再生の終了までオーディオによってトリガーされるイベント フローと、さまざまな期間で操作できる属性について説明します。
    loadstart: 読み込みの開始
    durationchange: オーディオの継続時間を取得します。持続時間属性を取得します);
    progress: オーディオのダウンロード (ダウンロード プロセスとともにトリガーされ、この時点でバッファー属性を取得できます);
    canplay: 読み込まれたオーディオだけで再生を開始できます (これもトリガーされます)。一時停止後に再生を開始するたび);
    canplaythrough: オーディオはすべてロードされます。
    timeupdate: 再生中 (currentTime 属性は同期的に更新されます)。変更済み);
    seeked: 現在の再生進行状況の変更が完了しました。
    ended: 再生が完了しました。
    これは、まれに使用される、リストされていないイベントがいくつかある場合があります。
    イベントトリガープロセス中、オーディオのロードが開始される前に、コントロール、ループ、ボリュームなどのプロパティを設定できます。





    全体の構造を決定します。プラグイン このメソッドは他の人が使用できるように npm で公開されているため、コードの記述にはオブジェクト指向のアプローチを使用します。ユーザーのニーズは異なるため、設計の開始時に多数の API と構成項目が公開されます。ほとんどのユーザーのニーズを満たします。
    私は es6 の構文に慣れてきたので、開発効率を考慮して全体のプロセスを es6 に基づいて開発しました。最終的には webpack と webpack-dev- を使用しました。 es6 と sass をコンパイルするためのサーバー、プロジェクトのパッケージ化、ローカルサーバーの構築。



  2. プレーヤーの UI とインタラクションを決定します:
    インターフェースについては人それぞれの考えがあると思いますので、ここでは詳しく説明しません。例として私が作成したプレーヤー UI を分解してみましょう

    。インターフェースからの一言 プレーヤーに必要な最も基本的な機能: 再生/一時停止、カバー/曲名/歌手表示、再生プログレスバー/ロードプログレスバー/プログレス操作機能、サイクルモード切り替え、プログレステキスト更新/曲の長さ、ミュート/音量サイズ制御、リスト表示ステータス制御、リスト項目をクリックして曲を切り替える
    ユーザーのニーズを満たして構成項目と API を提供したいという出発点と組み合わせることで、構成項目と公開された API 項目を取得できます。デザインしたい内容:
    設定項目:自動再生オンの有無、デフォルトソングリストの表示状態、デフォルトループモードの設定
    API:再生/一時停止/切り替え、ループモード切替、ミュート/再開、リスト表示ステータス切り替え、前の曲/次の曲/切り替え曲 、現在のインスタンスを破棄します



  3. プロジェクト構造を確立し、コーディングを開始します:

    webpack を使用するため、CSS を直接 js にパッケージ化して使用できるようにしますユーザー用のプラグインとして:

    require('./skPlayer.scss');
    ログイン後にコピー
    パブリック メソッドを抽出します。プレーヤーには、抽出する必要があるパブリック メソッドが多数あります。たとえば、再生プログレス バーと音量プログレス バーをクリックするときに、プログレスジャンプのためのマウスとプログレスバーの左端の間の距離を計算します。時間は duratin から標準時間形式などに変換します:

    const Util = {
        leftDistance: (el) => {
            let left = el.offsetLeft;
            let scrollLeft;while (el.offsetParent) {
                el = el.offsetParent;
                left += el.offsetLeft;
            }
            scrollLeft = document.body.scrollLeft + document.documentElement.scrollLeft;return left - scrollLeft;
        },
        timeFormat: (time) => {
            let tempMin = parseInt(time / 60);
            let tempSec = parseInt(time % 60);
            let curMin = tempMin < 10 ? (&#39;0&#39; + tempMin) : tempMin;
            let curSec = tempSec < 10 ? (&#39;0&#39; + tempSec) : tempSec;return curMin + &#39;:&#39; + curSec;
        },
        percentFormat: (percent) => {return (percent * 100).toFixed(2) + '%';
        },
        ajax: (option) => {
            option.beforeSend && option.beforeSend();
            let xhr = new XMLHttpRequest();
            xhr.onreadystatechange = () => {if(xhr.readyState === 4){if(xhr.status >= 200 && xhr.status < 300){
                        option.success && option.success(xhr.responseText);
                    }else{
                        option.fail && option.fail(xhr.status);
                    }
                }
            };
            xhr.open(&#39;GET&#39;,option.url);
            xhr.send(null);
        }
    };
    ログイン後にコピー
    初期の設計上、プレイヤーの一意性を考慮し、インスタンスは1つしか存在できないように設計されており、グローバル変数が設定されていました インスタンスが現在存在するかどうかを判定するには:
    let instance = false;
    ログイン後にコピー

    を使用する場合ES6 では、メインロジックをコンストラクター内に配置し、汎用性と API をパブリック関数内に配置します:

    class skPlayer {
        constructor(option){
        }
    
        template(){
        }
    
        init(){
        }
    
        bind(){
        }
    
        prev(){
        }
    
        next(){
        }
    
        switchMusic(index){
        }
    
        play(){
        }
    
        pause(){
        }
    
        toggle(){
        }
    
        toggleList(){
        }
    
        toggleMute(){
        }
    
        switchMode(){
        }
    
        destroy(){
        }
    }
    ログイン後にコピー
    View Code
    プロトタイプのない空のオブジェクトがあるかどうかをインスタンス判断します。コンストラクターはデフォルトでプロトタイプを持つインスタンスを返します:
            if(instance){
                console.error(&#39;SKPlayer只能存在一个实例!&#39;);return Object.create(null);
            }else{
                instance = true;
            }
    ログイン後にコピー

    構成項目を初期化します。デフォルト構成はユーザー構成とマージされます:
            const defaultOption = {
                ...
            };this.option = Object.assign({},defaultOption,option);
    ログイン後にコピー

    よく使用される属性はインスタンスにバインドされます:
            this.root = this.option.element;this.type = this.option.music.type;this.music = this.option.music.source;this.isMobile = /mobile/i.test(window.navigator.userAgent);
    ログイン後にコピー

    Some public API内部のthisはデフォルトでインスタンスを指しますが、コード量を減らすために、操作インターフェースやAPI上の関数呼び出しやイベントのバインドにコード一式を使用します この点が変わるので、これをバインドしますもちろん、イベントをバインドするときにアロー関数を使用することもできます:
            this.toggle = this.toggle.bind(this);this.toggleList = this.toggleList.bind(this);this.toggleMute = this.toggleMute.bind(this);this.switchMode = this.switchMode.bind(this);
    ログイン後にコピー

    次に、ES6 文字列テンプレートを使用して HTML の生成を開始し、それをページ上に挿入します:
                this.root.innerHTML = this.template();
    ログイン後にコピー

    次に、初期化します。初期化プロセス中に、共通の DOM ノードがバインドされ、構成項目が初期化され、操作インターフェースが初期化されます:
                this.init();
    ログイン後にコピー

        init(){this.dom = {
                cover: this.root.querySelector(&#39;.skPlayer-cover&#39;),
                playbutton: this.root.querySelector(&#39;.skPlayer-play-btn&#39;),
                name: this.root.querySelector(&#39;.skPlayer-name&#39;),
                author: this.root.querySelector(&#39;.skPlayer-author&#39;),
                timeline_total: this.root.querySelector(&#39;.skPlayer-percent&#39;),
                timeline_loaded: this.root.querySelector(&#39;.skPlayer-line-loading&#39;),
                timeline_played: this.root.querySelector(&#39;.skPlayer-percent .skPlayer-line&#39;),
                timetext_total: this.root.querySelector(&#39;.skPlayer-total&#39;),
                timetext_played: this.root.querySelector(&#39;.skPlayer-cur&#39;),
                volumebutton: this.root.querySelector(&#39;.skPlayer-icon&#39;),
                volumeline_total: this.root.querySelector(&#39;.skPlayer-volume .skPlayer-percent&#39;),
                volumeline_value: this.root.querySelector(&#39;.skPlayer-volume .skPlayer-line&#39;),
                switchbutton: this.root.querySelector(&#39;.skPlayer-list-switch&#39;),
                modebutton: this.root.querySelector(&#39;.skPlayer-mode&#39;),
                musiclist: this.root.querySelector(&#39;.skPlayer-list&#39;),
                musicitem: this.root.querySelectorAll(&#39;.skPlayer-list li&#39;)
            };this.audio = this.root.querySelector(&#39;.skPlayer-source&#39;);if(this.option.listshow){this.root.className = &#39;skPlayer-list-on&#39;;
            }if(this.option.mode === &#39;singleloop&#39;){this.audio.loop = true;
            }this.dom.musicitem[0].className = &#39;skPlayer-curMusic&#39;;
        }
    ログイン後にコピー
    View Code
    イベント バインディング、主にオーディオ イベントにバインドされます。および操作パネルのイベント:
                this.bind();
    ログイン後にコピー

        bind(){this.updateLine = () => {
                let percent = this.audio.buffered.length ? (this.audio.buffered.end(this.audio.buffered.length - 1) / this.audio.duration) : 0;this.dom.timeline_loaded.style.width = Util.percentFormat(percent);
            };// this.audio.addEventListener('load', (e) => {//     if(this.option.autoplay && this.isMobile){//         this.play();//     }// });this.audio.addEventListener('durationchange', (e) => {this.dom.timetext_total.innerHTML = Util.timeFormat(this.audio.duration);this.updateLine();
            });this.audio.addEventListener('progress', (e) => {this.updateLine();
            });this.audio.addEventListener('canplay', (e) => {if(this.option.autoplay && !this.isMobile){this.play();
                }
            });this.audio.addEventListener('timeupdate', (e) => {
                let percent = this.audio.currentTime / this.audio.duration;this.dom.timeline_played.style.width = Util.percentFormat(percent);this.dom.timetext_played.innerHTML = Util.timeFormat(this.audio.currentTime);
            });//this.audio.addEventListener('seeked', (e) => {//    this.play();//});this.audio.addEventListener('ended', (e) => {this.next();
            });this.dom.playbutton.addEventListener('click', this.toggle);this.dom.switchbutton.addEventListener('click', this.toggleList);if(!this.isMobile){this.dom.volumebutton.addEventListener('click', this.toggleMute);
            }this.dom.modebutton.addEventListener('click', this.switchMode);this.dom.musiclist.addEventListener('click', (e) => {
                let target,index,curIndex;if(e.target.tagName.toUpperCase() === 'LI'){
                    target = e.target;
                }else{
                    target = e.target.parentElement;
                }
                index = parseInt(target.getAttribute('data-index'));
                curIndex = parseInt(this.dom.musiclist.querySelector('.skPlayer-curMusic').getAttribute('data-index'));if(index === curIndex){this.play();
                }else{this.switchMusic(index + 1);
                }
            });this.dom.timeline_total.addEventListener('click', (event) => {
                let e = event || window.event;
                let percent = (e.clientX - Util.leftDistance(this.dom.timeline_total)) / this.dom.timeline_total.clientWidth;if(!isNaN(this.audio.duration)){this.dom.timeline_played.style.width = Util.percentFormat(percent);this.dom.timetext_played.innerHTML = Util.timeFormat(percent * this.audio.duration);this.audio.currentTime = percent * this.audio.duration;
                }
            });if(!this.isMobile){this.dom.volumeline_total.addEventListener('click', (event) => {
                    let e = event || window.event;
                    let percent = (e.clientX - Util.leftDistance(this.dom.volumeline_total)) / this.dom.volumeline_total.clientWidth;this.dom.volumeline_value.style.width = Util.percentFormat(percent);this.audio.volume = percent;if(this.audio.muted){this.toggleMute();
                    }
                });
            }
        }
    ログイン後にコピー
    コードを表示

    至此,核心代码基本完成,接下来就是自己根据需要完成API部分。
    最后我们暴露模块:

    module.exports = skPlayer;
    ログイン後にコピー

    一个HTML5音乐播放器就大功告成了 ~ !

以上がHTML5 音楽プレーヤーの例を実装するの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

関連ラベル:
ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート