从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组件(我不确定这是否相关)。
答案 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加载视频并在此之后停止侦听更改。它的编写方式使页面上的任意数量的视频都能正常工作。
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;
答案 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>