みかづきブログ その3

本ブログは更新を終了しました。通算140万ユーザーの方に観覧頂くことができました。長い間、ありがとうございました。

👆

引越し先はこちらです!

続々・YouTubeの埋め込みプレーヤーを管理するクラスをつくる

以前つくったクラス を複数のプレイヤーを生成しやすいように改修しました。

kimizuka.hatenablog.com


変更点

  • 純正のYouTubePlayerを返すように変更しました。
  • addEventListenerに渡したコールバックに渡る引数を変更しました。
  • イベント名をクラスの定数として定義しました。
  • オプションで自動再生するかどうかを渡せなくなりました。

JavaScript

(function(win) {
    
    "use strict";
    
    win.App = {};

})(this);

(function(win, doc, ns) {

    "use strict";

    function EventDispatcher() {
        this._events = {};
    }

    EventDispatcher.prototype.hasEventListener = function(eventName) {
        return !!this._events[eventName];
    };

    EventDispatcher.prototype.addEventListener = function(eventName, callback) {
        if (this.hasEventListener(eventName)) {
            var events = this._events[eventName],
                length = events.length,
                i = 0;
    
            for (; i < length; i++) {
                if (events[i] === callback) {
                    return;
                }
            }

            events.push(callback);
        } else {
            this._events[eventName] = [callback];
        }
    };

    EventDispatcher.prototype.removeEventListener = function(eventName, callback) {
        if (!this.hasEventListener(eventName)) {
            return;
        } else {
            var events = this._events[eventName],
                i = events.length,
                index;
    
            while (i--) {
                if (events[i] === callback) {
                    index = i;
                }
            }
    
            events.splice(index, 1);
        }
    };

    EventDispatcher.prototype.fireEvent = function(eventName, opt_this, opt_arg) {
        if (!this.hasEventListener(eventName)) {
            return;
        } else {
            var events     = this._events[eventName],
                copyEvents = _copyArray(events),
                arg        = _copyArray(arguments),
                length     = events.length,
                i = 0;
    
            // eventNameとopt_thisを削除
            arg.splice(0, 2);
    
            for (; i < length; i++) {
                copyEvents[i].apply(opt_this || this, arg);
            }
        }
    
        function _copyArray(array) {
            var newArray = [],
                i = 0;
    
            try {
                newArray = [].slice.call(array);
            } catch(e) {
                for (; i < array.length; i++) {
                    newArray.push(array[i]);
                }
            }
    
            return newArray;
        }
    };

    function YTPlayer() {
        var that = this;

        EventDispatcher.call(this);

        _init();

        function _init() {
            var tag            = doc.createElement("script"),
                firstScriptTag = doc.getElementsByTagName("script")[0];

            tag.src = "https://www.youtube.com/iframe_api";
            firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);

            function onYouTubeIframeAPIReady() {
                that.fireEvent(YTPlayer.EVENT.YOUTUBE_READY);
            }

            // export
            win.onYouTubeIframeAPIReady = onYouTubeIframeAPIReady;
        }

        function _onPlayerReady(id) { // 動画再生準備完了時イベント
            that.fireEvent(YTPlayer.EVENT.PLAYER_READY, this.target, {
                id     : id,
                player : this.target
            });
        }

        function _onPlayerStateChange(id) { // 動画再生状態変更時イベント
            switch (this.data) {
                case -1: // 未開始
                    that.fireEvent(YTPlayer.EVENT.UNSTARTED, this.target, {
                        id     : id,
                        player : this.target
                    });
                    break;
                case 0: // 再生終了時
                    that.fireEvent(YTPlayer.EVENT.ENDED_VIDEO, this.target, {
                        id     : id,
                        player : this.target
                    });
                    break;
                case 1: // 再生開始時
                    that.fireEvent(YTPlayer.EVENT.PLAYING_VIDEO, this.target, {
                        id     : id,
                        player : this.target
                    });
                    break;
                case 2: // 一時停止時
                    that.fireEvent(YTPlayer.EVENT.PAUSED_VIDEO, this.target, {
                        id     : id,
                        player : this.target
                    });
                    break;
                case 3: // バッファリング
                    that.fireEvent(YTPlayer.EVENT.BUFFERING_VIDEO, this.target, {
                        id     : id,
                        player : this.target
                    });
                    break;
//                case 5: // 頭出し済み
//                    break;
            }
        }

        /**
         * Playerを生成します
         * @param  {string}  id      // Player に置換する DOM の id属性(必須)
         * @param  {string}  videoId // YouTube の video ID(必須)
         * @param  {object}  opt_obj // オプション用のオブジェクト
         *         {number}  width       // プレイヤーの幅(省略時は640)
         *         {number}  height      // プレイヤーの高さ(省略時は480)
         * @return {object}  プレイヤーオブジェクト
         */
        function build(id, videoId, opt_obj) {
            var player = new YT.Player(id, {
                    width   : (opt_obj && opt_obj.width)  || 640, // 動画幅
                    height  : (opt_obj && opt_obj.height) || 480, // 動画高さ
                    videoId : videoId,       // 動画ID
                    events  : {
                        onReady : function(player) {
                            _onPlayerReady.call(player, id);
                        },
                        onStateChange : function(player) {
                            _onPlayerStateChange.call(player, id);
                        }
                    },
                    playerVars: {
                        rel      : 0, // 関連動画
                        showinfo : 0, // 動画情報
                        controls : 1, // コントローラー
                        wmode    : "transparent" // z-indexを有効にする
                    }
                });

            return player;
        }

        this.build = build;
    }

    YTPlayer.EVENT = {
        YOUTUBE_READY   : "youtubeready",
        PLAYER_READY    : "playerready",
        UNSTARTED       : "unstarted",
        ENDED_VIDEO     : "endedvideo",
        PLAYING_VIDEO   : "playingvideo",
        PAUSED_VIDEO    : "pausedvideo",
        BUFFERING_VIDEO : "bufferingvideo"
    };
    
    YTPlayer.prototype             = new EventDispatcher();
    YTPlayer.prototype.constructor = YTPlayer;

    ns.YTPlayer = {
        EVENT       : YTPlayer.EVENT,
        getInstance : function() {
            if (!YTPlayer.instance) {
                YTPlayer.instance = new YTPlayer();
            }

            return YTPlayer.instance;
        }
    };

})(this, document, App);

(function(win, doc, ns) {
    
    "use strict";
    
    var youTube = ns.YTPlayer.getInstance(),
        player;

    youTube.addEventListener(ns.YTPlayer.EVENT.YOUTUBE_READY, function() {
        player = youTube.build("player", "1g0ebPju_eE");
    });

    youTube.addEventListener(ns.YTPlayer.EVENT.PLAYER_READY, function(evt) {
        console.log(evt);
    });
    
    youTube.addEventListener(ns.YTPlayer.EVENT.PLAYING_VIDEO, function(evt) {
        console.log(evt);
    });
    
})(this, document, App);

DEMO



今回は以上です。