为页面上的多个实例生成新的 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();
                });
            })
        })
    }
});