如何嵌入多个Facebook视频(使用React)

时间:2017-01-10 10:16:31

标签: javascript facebook reactjs

Facebook docs阅读,嵌入Facebook视频似乎很容易。但是,<div id="fb-root"></div>必须位于脚本和fb-video类div之前(来自我观察到的)。因此,如果我想要嵌入视频,我必须执行以下操作:

<div className="card-video-wrapper">
    <div id="fb-root"></div>
    <script>(function(d, s, id) {
         var js, fjs = d.getElementsByTagName(s)[0];
         if (d.getElementById(id)) return;
         js = d.createElement(s); js.id = id;
         js.src = "//connect.facebook.net/es_ES/sdk.js#xfbml=1&version=v2.8";
         fjs.parentNode.insertBefore(js, fjs);
    }(document, 'script', 'facebook-jssdk'));</script>
    <div className="fb-video" data-href="my-video-url" data-show-text="false" data-autoplay="true"></div>
</div>

我首先要知道<div id="fb-root"></div>和脚本应该在打开的正文标记之后,但这样视频会隐藏在页面顶部。

当我想要嵌入多个Facebook视频时会遇到问题:

<div className="card-video-wrapper">
    <div id="fb-root"></div>
    <script>(function(d, s, id) {
         var js, fjs = d.getElementsByTagName(s)[0];
         if (d.getElementById(id)) return;
         js = d.createElement(s); js.id = id;
         js.src = "//connect.facebook.net/es_ES/sdk.js#xfbml=1&version=v2.8";
         fjs.parentNode.insertBefore(js, fjs);
    }(document, 'script', 'facebook-jssdk'));</script>
    <div className="fb-video" data-href="my-video-url-1" data-show-text="false" data-autoplay="true"></div>
</div>
<div className="card-video-wrapper">
    <div id="fb-root"></div>
    <script>(function(d, s, id) {
         var js, fjs = d.getElementsByTagName(s)[0];
         if (d.getElementById(id)) return;
         js = d.createElement(s); js.id = id;
         js.src = "//connect.facebook.net/es_ES/sdk.js#xfbml=1&version=v2.8";
         fjs.parentNode.insertBefore(js, fjs);
    }(document, 'script', 'facebook-jssdk'));</script>
    <div className="fb-video" data-href="my-video-url-2" data-show-text="false" data-autoplay="true"></div>
</div>

在这种情况下,不显示第二个。

可能会<div id="fb-root"></div>被放置一次,但正如我所说的那样,视频被隐藏了。让我们看一个例子:

<body>
    <div id="fb-root"></div>
    <script>(function(d, s, id) {
         var js, fjs = d.getElementsByTagName(s)[0];
         if (d.getElementById(id)) return;
         js = d.createElement(s); js.id = id;
         js.src = "//connect.facebook.net/es_ES/sdk.js#xfbml=1&version=v2.8";
         fjs.parentNode.insertBefore(js, fjs);
    }(document, 'script', 'facebook-jssdk'));</script>

    ...

    <div className="card-video-wrapper">
        <div className="fb-video" data-href="my-video-url-1" data-show-text="false" data-autoplay="true"></div>
    </div>
    <div className="card-video-wrapper">
        <div className="fb-video" data-href="my-video-url-2" data-show-text="false" data-autoplay="true"></div>
    </div>

    ...

</body>

使用导航器控制台检查我看到这些样式应用于fb-root图层的子项:

position: absolute;
top: -10000px;
height: 0px;
width: 0px;

嵌入多个Facebook视频的方式是什么?

修改

有人会认为它必须与CSS有关。但是,即使删除所有CSS规则,我也会看到同样的问题,当<div id="fb-root"></div>和脚本放在起始正文标记之后时,视频不会显示(甚至只显示一个视频)。

另一方面,我用一个简单的页面(如@hackerrdave建议的那样)对它进行了测试,并且它有效。现在我想知道可能是什么问题。它是一个React应用程序,使用了一些Framework7组件(我不确定这是否相关)。

4 个答案:

答案 0 :(得分:4)

使用 React 是相关的,因为第一个DOM渲染不包含任何fb-video元素。

问题是当组件接收要渲染的元素时,会呈现fb-video元素。然后,当SDK加载时,没有要呈现的视频。如果我在收到元素后加载SDK,则会显示视频。

修改

感谢@CBroe的提示。更好的解决方案是在componentDidMount和/或componentDidUpdate函数中使用FB.XFBML.parse();。通过这种方式,我可以将<div id="fb-root"></div>和脚本放在body标签之后。

componentDidMount() {
    FB.XFBML.parse();
}
componentDidUpdate() {
    FB.XFBML.parse();
}

答案 1 :(得分:1)

这是一种解决方法,因为我无法准确找到问题,但无论如何我都在回答,因为它会导致一些可行的问题。你被警告了。

我发现Facebook SDK增加了一个不知何故阻碍的范围。通过创建自己的iframe具有完全相同的src和其他一些属性,视频将正常显示。如果Facebook在某个地方有一个回调指示何时完成加载,我们可以使用它来做到这一点。但是,我找不到这样的回调,所以我决定使用MutationObserver

解决方案的内容在下面的onFacebookLoaded函数中。虽然我没有使用React,但我很确定它也应该在那里工作。显然,你可以改变你感兴趣的属性 - 其中有allowfullscreen,这可能很重要。

以下代码的其余部分仅等待Facebook加载视频并在此之后停止侦听更改。它的编写方式使页面上的任意数量的视频都能正常工作。

&#13;
&#13;
var onFacebookLoaded = function() {
      // replace .fb-video div with iframe
      var oldFrame = this.querySelector('iframe'),
          newFrame = document.createElement('iframe'),
          attrsWeWant = new Set();
      attrsWeWant.add('src').add('scrolling').add('title')
      .add('width').add('height').add('frameborder');
      if (oldFrame.hasAttributes()) {
        var attrs = oldFrame.attributes;
        for (let i = attrs.length - 1; i >= 0; --i) {
          if (attrsWeWant.has(attrs[i].name)) {
            newFrame.setAttribute(attrs[i].name, attrs[i].value);
          }
        }
      }
      this.parentNode.replaceChild(newFrame, this);
    },
    target = document.querySelectorAll('.fb-video'),
    count = target.length,
    observer = new MutationObserver(function(mutations) {
      mutations.forEach(function(mutation) {
        if (mutation.target.fbLoadedSeen !== true) {
          onFacebookLoaded.call(mutation.target);
          mutation.target.fbLoadedSeen = true;
          count--;
        }
      });

      // cleanup when all videos have loaded
      if (count === 0) {
        observer.disconnect();
      }
    });

// connect to updates
for (let i = 0; i < target.length; ++i) {
  observer.observe(target.item(i), {attributes: true});
}
&#13;
<div id="fb-root"></div>
<script>
  (function(d, s, id) {
    var js, fjs = d.getElementsByTagName(s)[0];
    if (d.getElementById(id)) {
      return;
    }
    js = d.createElement(s); js.id = id;
    js.src = "https://connect.facebook.net/en_US/sdk.js#xfbml=1&version=v2.8";
    fjs.parentNode.insertBefore(js, fjs);
  }(document, 'script', 'facebook-jssdk'));
</script>

<h1>Video 1</h1>
<div class="fb-video"
     data-href="https://www.facebook.com/facebook/videos/10153231379946729/"
     data-width="300"
     data-height="300"
     data-allowfullscreen="true"></div>

<h1>Video 2</h1>
<div class="fb-video"
     data-href="https://www.facebook.com/facebook/videos/10153231379946729/"
     data-width="500"
     data-height="400"
     data-allowfullscreen="true"></div>
&#13;
&#13;
&#13;

答案 2 :(得分:1)

  

[来自OP的其他答案]问题是当组件接收要渲染的元素时,将呈现fb-video元素。然后,当SDK加载时,没有要呈现的视频。如果我在收到元素后加载SDK,则会显示视频。

是的,SDK会浏览文档并在初始化时查找解析的元素。

但是有一个专门用于渲染SDK初始化后添加到文档中的内容的方法:{{3}}

可以在没有任何参数的情况下调用它来再次查看整个文档,或者可以传递一个DOM元素,这样它只能查看特定的DOM子树。

答案 3 :(得分:0)

根据FB文档,您应该只放置SDK和fb-root div一次:

<!-- Load Facebook SDK for JavaScript -->
<div id="fb-root"></div>
<script>(function(d, s, id) {
  var js, fjs = d.getElementsByTagName(s)[0];
  if (d.getElementById(id)) return;
  js = d.createElement(s); js.id = id;
  js.src = "//connect.facebook.net/en_US/sdk.js#xfbml=1&version=v2.6";
  fjs.parentNode.insertBefore(js, fjs);
}(document, 'script', 'facebook-jssdk'));</script>

然后,对于要显示的每个视频,您可以放置​​嵌入式视频播放器div:

<!-- Your embedded video player code -->
<div class="fb-video" data-href="https://www.facebook.com/facebook/videos/10153231379946729/" data-width="500" data-show-text="false"></div>
<div class="fb-video" data-href="https://www.facebook.com/facebook/videos/10153231379946729/" data-width="500" data-show-text="false"></div>