为页面上的多个实例生成新的 iframe YouTube 播放器
Generate new iframe YouTube player for multiple instances on a page
当我在一个页面上只有一个 YouTube 视频实例时,以下 JavaScript 效果很好:
function createVideo(playerElement, videoID, autoplay=false) {
const youtubeScriptId = 'youtube-api';
const youtubeScript = document.getElementById(youtubeScriptId);
if (youtubeScript === null) {
const tag = document.createElement('script');
const firstScript = document.getElementsByTagName('script')[0];
tag.src = 'https://www.youtube.com/iframe_api';
tag.id = youtubeScriptId;
firstScript.parentNode.insertBefore(tag, firstScript);
}
window.onYouTubeIframeAPIReady = function() {
return new window.YT.Player(playerElement, {
videoId: videoID,
playerVars: {
autoplay: autoplay,
modestbranding: 1,
rel: 0
}
});
}
}
但是当我尝试再次调用它时,视频没有加载。只有第一个视频。 页面加载后通过点击事件调用此方法,我传入 videoID
数据属性并构建新的 YouTube 视频以显示在页面上。
我假设是因为我的 JavaScript 只在 window
对象上创建一个实例,而不是分隔多个实例。经过进一步研究,我可以看到 onYouTubeIframeAPIReady()
方法只在页面上触发一次,这就解释了为什么在点击事件触发此方法时后续调用失败。由于我不可能知道在页面上加载多少个确切实例,我将如何重构此代码以使其动态化,以便可以在页面 via click events only
上创建和播放 unlimited instances
?当您了解页面上的元素时,我看过无数关于构建 YouTube 视频的教程。但在这种情况下,要么我不知道 DOM 上有什么,要么想通过构建要插入到 DOM 中的无限 YT 视频来减慢网站的页面加载速度,但可能不会被点击由用户播放。
甚至可以使用绑定到点击事件的 YT API 在页面上动态创建新的 YouTube 视频吗?从我在网上阅读的内容来看,当 onYouTubeIframeAPIReady()
在 YT API 加载后首次加载到页面上时,似乎有人必须一次加载所有视频,我必须在适当的位置添加额外的逻辑每个 play/stop,然后为每个视频绑定额外的点击事件以显示/隐藏/play/stop。这将显着增加我的页面负载,并向我的页面添加一堆 JS 悬垂。我只是想在点击事件上创建一个新视频。
我希望您不会每次都使用相同的视频 ID,因为对于任何事物的多个实例,您需要进行某种顺序 ID 管理,就像这样...
var ID=[], Vid;
for(var i=0; i<20; i++){ // create 20 video players
ID.push('V'+i);
Vid=document.createElement('video');
Vid.id=ID[i];
document.body.appendChild(Vid);
createVideo(e, ID[i], false); // Your function
}
你明白了...
当你不知道有多少玩家可以使用随机数来避免冲突...
var ID=[]; // Global array
function AddVideoPlayer(){
var Vid, i=ID.length-1;
ID.push('V'+RandomNumber(99999999));
Vid=document.createElement('video');
Vid.id=ID[i];
document.body.appendChild(Vid);
createVideo(e, ID[i], false); // Your function
}
您遇到的核心问题是 YT.Player 只能在页面上初始化一次 - 如果您有多个视频要通过 YT.Player 处理,您必须使用相同的 YT.Player 实例一个一个地迭代视频。起初有点奇怪,但可以工作 - 特别是如果您需要通过弹出模式等处理视频时。
下面是一个示例,我用它来迭代具有多个带视频的隐藏模态的页面,然后处理点击事件和播放视频:
jQuery(document).ready(function ($) {
let modalTriggerElements = $('.video_play_icon'),
playerInfoList = [],
players = []
if (typeof (YT) == 'undefined' || typeof (YT.Player) == 'undefined') {
let tag = document.createElement('script'),
firstScript = document.getElementsByTagName('script')[0]
tag.src = 'https://www.youtube.com/iframe_api';
tag.id = 'youtube-api';
firstScript.parentNode.insertBefore(tag, firstScript)
}
if (modalTriggerElements.length > 0) {
$.each(modalTriggerElements, (index, element) => {
buildPlayersList(element)
modalTriggerClickEvent(element)
})
}
window.onYouTubePlayerAPIReady = function () {
if (typeof playerInfoList === 'undefined') return;
for (let i = 0; i < playerInfoList.length; i++) {
players[i] = createPlayer(playerInfoList[i]);
}
}
function createPlayer(playerInfo) {
return new YT.Player(playerInfo.playerId, {
videoId: playerInfo.videoId,
playerVars: {
showinfo: 0,
}
});
}
function buildPlayersList(element) {
let $modelDiv = $(element).closest('.hc_module').next('.video_model'),
$playerDiv = $($modelDiv).find('#video-player');
playerInfoList.push({
'videoId': $($modelDiv).data('video-id'),
'playerId': $($playerDiv)[0],
});
}
function modalTriggerClickEvent(element) {
$(element).on('click', () => {
let $parentDiv = $(element).closest('.hc_module'),
$nearestVideoDiv = $parentDiv.next('.video_model'),
$closeDiv = $nearestVideoDiv.find('.close_modal')
$nearestVideoDiv.css('display', 'block')
$nearestVideoDiv.attr('aria-hidden', 'false')
$closeDiv.on('click', () => {
$nearestVideoDiv.css('display', 'none')
$nearestVideoDiv.attr('aria-hidden', 'true')
players.forEach((el) => {
el.stopVideo();
});
})
})
}
});
当我在一个页面上只有一个 YouTube 视频实例时,以下 JavaScript 效果很好:
function createVideo(playerElement, videoID, autoplay=false) {
const youtubeScriptId = 'youtube-api';
const youtubeScript = document.getElementById(youtubeScriptId);
if (youtubeScript === null) {
const tag = document.createElement('script');
const firstScript = document.getElementsByTagName('script')[0];
tag.src = 'https://www.youtube.com/iframe_api';
tag.id = youtubeScriptId;
firstScript.parentNode.insertBefore(tag, firstScript);
}
window.onYouTubeIframeAPIReady = function() {
return new window.YT.Player(playerElement, {
videoId: videoID,
playerVars: {
autoplay: autoplay,
modestbranding: 1,
rel: 0
}
});
}
}
但是当我尝试再次调用它时,视频没有加载。只有第一个视频。 页面加载后通过点击事件调用此方法,我传入 videoID
数据属性并构建新的 YouTube 视频以显示在页面上。
我假设是因为我的 JavaScript 只在 window
对象上创建一个实例,而不是分隔多个实例。经过进一步研究,我可以看到 onYouTubeIframeAPIReady()
方法只在页面上触发一次,这就解释了为什么在点击事件触发此方法时后续调用失败。由于我不可能知道在页面上加载多少个确切实例,我将如何重构此代码以使其动态化,以便可以在页面 via click events only
上创建和播放 unlimited instances
?当您了解页面上的元素时,我看过无数关于构建 YouTube 视频的教程。但在这种情况下,要么我不知道 DOM 上有什么,要么想通过构建要插入到 DOM 中的无限 YT 视频来减慢网站的页面加载速度,但可能不会被点击由用户播放。
甚至可以使用绑定到点击事件的 YT API 在页面上动态创建新的 YouTube 视频吗?从我在网上阅读的内容来看,当 onYouTubeIframeAPIReady()
在 YT API 加载后首次加载到页面上时,似乎有人必须一次加载所有视频,我必须在适当的位置添加额外的逻辑每个 play/stop,然后为每个视频绑定额外的点击事件以显示/隐藏/play/stop。这将显着增加我的页面负载,并向我的页面添加一堆 JS 悬垂。我只是想在点击事件上创建一个新视频。
我希望您不会每次都使用相同的视频 ID,因为对于任何事物的多个实例,您需要进行某种顺序 ID 管理,就像这样...
var ID=[], Vid;
for(var i=0; i<20; i++){ // create 20 video players
ID.push('V'+i);
Vid=document.createElement('video');
Vid.id=ID[i];
document.body.appendChild(Vid);
createVideo(e, ID[i], false); // Your function
}
你明白了...
当你不知道有多少玩家可以使用随机数来避免冲突...
var ID=[]; // Global array
function AddVideoPlayer(){
var Vid, i=ID.length-1;
ID.push('V'+RandomNumber(99999999));
Vid=document.createElement('video');
Vid.id=ID[i];
document.body.appendChild(Vid);
createVideo(e, ID[i], false); // Your function
}
您遇到的核心问题是 YT.Player 只能在页面上初始化一次 - 如果您有多个视频要通过 YT.Player 处理,您必须使用相同的 YT.Player 实例一个一个地迭代视频。起初有点奇怪,但可以工作 - 特别是如果您需要通过弹出模式等处理视频时。
下面是一个示例,我用它来迭代具有多个带视频的隐藏模态的页面,然后处理点击事件和播放视频:
jQuery(document).ready(function ($) {
let modalTriggerElements = $('.video_play_icon'),
playerInfoList = [],
players = []
if (typeof (YT) == 'undefined' || typeof (YT.Player) == 'undefined') {
let tag = document.createElement('script'),
firstScript = document.getElementsByTagName('script')[0]
tag.src = 'https://www.youtube.com/iframe_api';
tag.id = 'youtube-api';
firstScript.parentNode.insertBefore(tag, firstScript)
}
if (modalTriggerElements.length > 0) {
$.each(modalTriggerElements, (index, element) => {
buildPlayersList(element)
modalTriggerClickEvent(element)
})
}
window.onYouTubePlayerAPIReady = function () {
if (typeof playerInfoList === 'undefined') return;
for (let i = 0; i < playerInfoList.length; i++) {
players[i] = createPlayer(playerInfoList[i]);
}
}
function createPlayer(playerInfo) {
return new YT.Player(playerInfo.playerId, {
videoId: playerInfo.videoId,
playerVars: {
showinfo: 0,
}
});
}
function buildPlayersList(element) {
let $modelDiv = $(element).closest('.hc_module').next('.video_model'),
$playerDiv = $($modelDiv).find('#video-player');
playerInfoList.push({
'videoId': $($modelDiv).data('video-id'),
'playerId': $($playerDiv)[0],
});
}
function modalTriggerClickEvent(element) {
$(element).on('click', () => {
let $parentDiv = $(element).closest('.hc_module'),
$nearestVideoDiv = $parentDiv.next('.video_model'),
$closeDiv = $nearestVideoDiv.find('.close_modal')
$nearestVideoDiv.css('display', 'block')
$nearestVideoDiv.attr('aria-hidden', 'false')
$closeDiv.on('click', () => {
$nearestVideoDiv.css('display', 'none')
$nearestVideoDiv.attr('aria-hidden', 'true')
players.forEach((el) => {
el.stopVideo();
});
})
})
}
});