2

Я работаю с API iFrame YouTube, чтобы вставлять несколько видео на страницу. Документация здесь: https://developers.google.com/youtube/iframe_api_reference#RequirementsБезопасное определение переменных для общедоступных функций обратного вызова в javascript

Таким образом, вы загрузите API асинхронно, используя следующий фрагмент кода:

var tag = document.createElement('script'); 
tag.src = "http://www.youtube.com/player_api"; 
var firstScriptTag = document.getElementsByTagName('script')[0]; 
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag); 

После загрузки API запускает встроенную функцию обратного вызова onYouTubePlayerAPIReady.

Дополнительный контекст: Я определяю файл библиотеки для этого в Google Closure. Я предоставляю пространство имен: goog.provide('yt.video');

Затем я использую goog.exportSymbol, чтобы API мог найти эту функцию. Все работает отлично.

Мой вызов состоит в том, что я хотел бы передать 2 переменные функции обратного вызова. Есть ли способ сделать это без определения этих 2 переменных в контексте объекта window?

goog.provide('yt.video'); 

goog.require('goog.dom'); 

yt.video = function(videos, locales) { 
    this.videos = videos; 
    this.captionLocales = locales; 

    this.init(); 
}; 

yt.video.prototype.init = function() { 
    var tag = document.createElement('script'); 
    tag.src = "http://www.youtube.com/player_api"; 
    var firstScriptTag = document.getElementsByTagName('script')[0]; 
    firstScriptTag.parentNode.insertBefore(tag, firstScriptTag); 
}; 

/* 
* Callback function fired when YT API is ready 
* This is exported using goog.exportSymbol in another file and 
* is being fired by the API properly. 
*/ 
yt.video.prototype.onPlayerReady = function(videos, locales) { 
    window.console.log('this :' + this); //logs window 
    window.console.log('this.videos : ' + this.videos); //logs undefined 
    /* 
    * Video settings from Django variable 
    */ 
    for(i=0; i<this.videos.length; i++) { 
     var playerEvents = {}; 
     var embedVars = {}; 

     var el = this.videos[i].el; 
     var playerVid = this.videos[i].vid; 
     var playerWidth = this.videos[i].width; 
     var playerHeight = this.videos[i].height; 
     var captionLocales = this.videos[i].locales; 
     if(this.videos[i].playerVars) 
     var embedVars = this.videos[i].playerVars; 
     } 
     if(this.videos[i].events) { 
     var playerEvents = this.videos[i].events; 
     } 

     /* 
     * Show captions by default 
     */ 
     if(goog.array.indexOf(captionLocales, 'es') >= 0) { 
     embedVars.cc_load_policy = 1; 
     }; 

     new YT.Player(el, { 
     height: playerHeight, 
     width: playerWidth, 
     videoId: playerVid, 
     events: playerEvents, 
     playerVars: embedVars 
    }); 
}; 

};

Чтобы инициализировать это, я в настоящее время с помощью следующих пределов самостоятельного выполнения анонимной функции:

var videos = [ 
    {"vid": "video_id", "el": "player-1", "width": 640, "height": 390, "locales": ["es", "fr"], "events": {"onStateChange": stateChanged}}, 
    {"vid": "video_id", "el": "player-2", "locales": ["es", "fr"], "width": 640, "height": 390} 
    ]; 

    var locales = ['es']; 

    var videoTemplate = new yt.video(videos, locales); 

ответ

2

Как об определении onYouTubePlayerAPIReady как глобальная функция, как, как API ожидает, а затем вызвать ваш onPlayerReady метод из внутри этой функции? Пример кода:

window.onYouTubePlayerAPIReady = function() { 
    var args = Array.prototype.slice.call(arguments); 
    args.push(videos, locales); 
    videoTemplate.onPlayerReady.apply(videoTemplate, args); 
}; 

И изменить подпись onPlayerReady метода принимать аргументы, в том же порядке

+0

Спасибо за ваш ответ! Это умная идея. Если бы я хотел избежать изменения окна для этого, можете ли вы придумать какое-либо другое решение? Думаю, я застрял в этом подходе, если API предполагает, что window.onYouTubePlayerAPReady, правильно? – djreed

+1

Да, я думаю, что если API ожидает такого определения, возможно, не будет другого подхода, о котором я могу думать. Если вас беспокоит загрязнение глобального пространства имен (в этом случае окно), вы всегда можете свернуть значение onYouTubePlayerAPIReady после выполнения задания, то есть window.onYouTubePlayerAPIReady = null в качестве последней строки внутри метода onYouTubePlayerAPIReady –

1

Чтобы ответить на ваш конкретный вопрос:

Моя задача состоит в том, что я хотел бы передать 2 для функции обратного вызова. Есть ли способ сделать это без определения этих двух переменных в контексте объекта окна?

Да, есть способы предоставить данные функции обратного вызова без использования глобальных переменных. Однако, прежде чем смотреть на функцию обратного вызова API YouTube имеет следующее требование:

In addition, any HTML page that contains the YouTube player must implement a JavaScript function named onYouTubePlayerReady. The API will call this function when the player is fully loaded and the API is ready to receive calls.

Приложение YouTube API examples добавлять обработчики событий в функции onYouTubePlayerReady, как показано здесь:

function onYouTubePlayerAPIReady() { 
    var player; 
    player = new YT.Player('player', { 
    width: 1280, 
    height: 720, 
    videoId: 'u1zgFlCw8Aw', 
    events: { 
     'onReady': onPlayerReady, 
     'onPlaybackQualityChange': onPlayerPlaybackQualityChange, 
     'onStateChange': onPlayerStateChange, 
     'onError': onPlayerError 
    } 
    }); 
} 

Появляется tha t ваша функция обратного вызова вашего примера yt.video.prototype.onPlayerReady предназначена для прослушивания событий для события API YouTube onReady, испускаемого объектом YouTube YT.Player. В документах API указано, что прослушиватели событий добавляются либо при создании объекта YT.Player, либо добавляются с использованием функции addEventListener (альтернатива Closure Library - goog.events.listen).

Поскольку слушатель yt.video.prototype.onPlayerReady события должно «прослушивать» для onReady события, испускаемого из YT.Player объекта YouTube, было бы круговую строить новые YT.Player экземпляров в пределах слушателя событий yt.video.prototype.onPlayerReady предназначенных для прослушивания события, испускаемого YT.Player экземпляра ,

Возвращаясь к первоначальному вопросу о предоставлении данных в функцию обратного вызова без использования глобальных переменных, вы не можете передать произвольные аргументы функции к слушателю событий (например, в исходном примере коды выше, yt.video.prototype.onPlayerReady должен принять Event объект как его первый аргумент, а не массив videos). Тем не менее, прослушиватель событий yt.video.prototype.onPlayerReady может использоваться как функция обратного вызова и по-прежнему обращаться к состоянию объектов yt.video, если он равен , связанным с экземплярами yt.video.

Один из способов привязать аргумент this к определенному объекту с помощью функции Closure Librarygoog.bind(functionToCall, selfObject, var_args). yt.video конструктор может быть изменен следующим образом:

goog.provide('yt.video'); 

goog.require('goog.dom'); 

/** 
* @constructor 
*/ 
yt.video = function(videos, locales) { 
    this.videos = videos; 
    this.captionLocales = locales; 

    this.onPlayerReadyListener = goog.bind(this.onPlayerReady, this); 

    this.init(); 
}; 

yt.video.prototype.init = function() { 
    var tag = document.createElement('script'); 
    tag.src = "http://www.youtube.com/player_api"; 
    var firstScriptTag = document.getElementsByTagName('script')[0]; 
    firstScriptTag.parentNode.insertBefore(tag, firstScriptTag); 
}; 

/* 
* Callback function fired when YT API is ready 
* This is exported using goog.exportSymbol in another file and 
* is being fired by the API properly. 
*/ 
yt.video.prototype.onPlayerReady = function(event) { 
    // Logs [object Object] 
    window.console.log('this :' + this); 

    // Logs [object Object],[object Object] 
    window.console.log('this.videos : ' + this.videos); 

    event.target.playVideo(); 
}; 


Тогда оценка слушателя событий может быть добавлен к YT.Player объекта следующим образом:

var myVideoObject = new yt.video(videos, locales); 

function onYouTubePlayerAPIReady() { 
    var player; 
    player = new YT.Player('player', { 
    width: 1280, 
    height: 720, 
    videoId: 'u1zgFlCw8Aw', 
    events: { 
     'onReady': myVideoObject.onPlayerReadyListener 
    } 
    }); 
} 
+0

Спасибо за ваш ответ ! Фактически я дал привязку. this.onPlayerReadyListener = goog.bind (this.onPlayerReady, this); похоже, не работает. this.video все еще не определено из yt.video.prototype.onPlayerReady. Любая идея почему? – djreed

+0

@djreed: см. Приведенный выше пример кода на основе тестирования в Chrome. Внутри 'yt.video.prototype.onPlayerReady',' this.videos' теперь успешно записывает '[object Object], [object Object]' вместо 'undefined'. Слушатель событий для 'onStateChange' был изменен на' yt.onPlayerStateChange'. Кроме того, в качестве стиля может быть полезно использовать другое пространство имен для вашей библиотеки ('yt' versus' YT' может ввести в заблуждение). –

+0

Можете ли вы объяснить, почему вы добавили функцию onYouTubePlayerAPIReady? Эта функция уже определена как yt.video.prototype.onPlayerReady – djreed

Смежные вопросы