我已经将问题追溯到FB.XFBML.parse()使用的html5Info函数。它有条件。这是两个元素不同的布尔语句:element.getAttribute('fb-xfbml-state')
变为"rendered"
(truthy)或null
(falsy),具体取决于处理的元素。
为什么我的ember-component的呈现HTML没有将'fb-xfbml-state'设置为“呈现”而模板中的静态HTML有?
Dirtyfixxed我的问题是让我的facebook组件包含这样的.setAttribute调用。
/* global FB */
import Ember from 'ember';
export default Ember.Component.extend({
tagName: 'div',
classNames: 'fb-share-button',
attributeBindings: [
'data-href',
'data-layout',
'data-action',
'data-show-faces',
'data-share'
],
onDidInsertElement: function() {
Ember.run.debounce(this, function() {
console.log(document)
_.forEach(document.getElementsByClassName('fb-share-button'), function(element) {
element.setAttribute('fb-xfbml-state', 'rendered');
});
FB.XFBML.parse();
}, 250);
}.on('didInsertElement'),
});
组件似乎生成子节点,如document.getElementById('myComponentElementInTheDOM').childNodes
中所示,这些是组件生成的HTML与纯HTML之间的区别。 FB-SDK有一个条件IF语句,对于没有childNodes的普通HTML产生true,而对于生成具有子节点的HTML的组件产生false,导致仅将纯HTML视为要呈现的目标。
我有一种情况,我使用chrome检查器检查DOM,我找到两个相同的html片段:
<div id="ember403" class="ember-view fb-share-button" data-href="https://mypage.com" data-layout="button_count" data-action="like" data-show-faces="false" data-share="true"></div>
<div id="ember407" class="ember-view fb-share-button" data-href="https://mypage.com" data-layout="button_count" data-action="like" data-show-faces="false" data-share="true"></div>
其中一个在路由把手文件中作为纯HTML放置,另一个用我制作的Ember组件渲染。在页面加载后手动调用FB.XFBML.parse()时,只能找到一个。
我使用了facebook SDK的debug.js版本,当我调用FB.XFBML.parse()时,它说:
XFBML Parsing Finish 2, 1 tags found
// Debug version: connect.facebook.net/en_US/all/debug.js
// Normal version: connect.facebook.net/en_US/sdk.js
如果我现在首先使用chrome检查器以某种超级方式修改DOM,比如添加一个新的空白行。我可以再次致电FB.XFBML.parse()
并突然找到两个标签。
我可以做些什么来使我的ember组件生成的HTML能够被FB.XFMBL.parse()找到,就像路由把手文件中纯HTML生成的HTML一样?
{{social-facebook data-href="https://mypage.com" data-layout="button_count" data-action="like" data-show-faces="false" data-share="true"}}
<div id="ember407" class="ember-view fb-share-button" data-href="https://mypage.com" data-layout="button_count" data-action="like" data-show-faces="false" data-share="true"></div>
以上代码在chrome inspector中显示以下内容:
/* global FB */
import Ember from 'ember';
export default Ember.Component.extend({
tagName: 'div',
classNames: 'fb-share-button',
attributeBindings: [
'data-href',
'data-layout',
'data-action',
'data-show-faces',
'data-share'
],
onDidInsertElement: function() {
Ember.run.schedule('afterRender', FB.XFBML.parse);
}.on('didInsertElement'),
});
{{yield}}
/* global FB */
import ENV from '../config/environment';
export function initialize(container, application) {
var debug = false;
// Wait for Facebook to load before allowing the application
// to fully boot. This prevents `ReferenceError: FB is not defined`
application.deferReadiness();
var fbAsyncInit = function() {
console.log("SOCIAL DEBUG: fbAsyncInit invoked.");
initFacebook(window.FB);
application.advanceReadiness();
};
loadFacebookSDK(debug);
window.fbAsyncInit = fbAsyncInit;
}
function initFacebook(FB) {
console.log("SOCIAL DEBUG: FB.init invoked.", ENV.fbAppId, ENV.fbSDKVersion);
FB.init({
appId : ENV.fbAppId,
xfbml : true,
version : ENV.fbSDKVersion
});
}
function loadFacebookSDK(debug) {
(function(d, s, id){
console.log("SOCIAL DEBUG: Load facebook SDK code", d, s, id);
var js, fjs = d.getElementsByTagName(s)[0];
if (d.getElementById(id)) {return;}
js = d.createElement(s); js.id = id;
js.src = debug ? "//connect.facebook.net/en_US/all/debug.js" : "//connect.facebook.net/sv_SE/sdk.js";
fjs.parentNode.insertBefore(js, fjs);
}(document, 'script', 'facebook-jssdk'));
}
export default {
name: 'social-facebook',
initialize: initialize
};
答案 0 :(得分:2)
此组件代码可用于解决由组件创建的隐藏childNode以处理数据绑定所引起的问题。这个解决方案尽可能接近完美,因为我无法调整ember组件和facebook sdk的工作方式。
/* global FB */
import Ember from 'ember';
export default Ember.Component.extend({
tagName: 'div',
classNames: 'fb-share-button',
attributeBindings: [
'data-href',
'data-layout',
'data-action',
'data-show-faces',
'data-share'
],
onDidInsertElement: function() {
// This is needed to make the FB SDK accept the component rendered HTML even though child nodes due to databinding exists
// To understand more about this, follow the code inside connect.facebook.net/en_US/all/debug.js
// 1: Read up on the function FB.XFBML.parse, found by searching for: 'function parse(/*DOMElement*/ dom'
// 2: Read up on the function html5Info, whos returnvalue will be affected, found by searching for: 'function html5Info('
// 3: Notice the conditional inside html5Info containing the booleans below:
// element.childNodes.length === 0 --- supposed to evaluate to true, but isn't due to childNodes used for databinding
// element.getAttribute('fb-xfbml-state') --- used to make sure that the conditional becomes true for the component
document.getElementById(this.get('elementId')).setAttribute('fb-xfbml-state', 'rendered');
// This makes FB-SDK render the HTML-stubs inserted by the ember components
Ember.run.debounce(this, FB.XFBML.parse, 100);
}.on('didInsertElement'),
});
/* global FB */
import ENV from '../config/environment';
export function initialize(container, application) {
var debug = true;
// Wait for Facebook to load before allowing the application
// to fully boot. This prevents `ReferenceError: FB is not defined`
application.deferReadiness();
var fbAsyncInit = function() {
initFacebook(window.FB);
application.advanceReadiness();
};
loadFacebookSDK(debug);
window.fbAsyncInit = fbAsyncInit;
}
function initFacebook(FB) {
FB.init({
appId : ENV.fbAppId,
xfbml : true,
version : ENV.fbSDKVersion
});
}
function loadFacebookSDK(debug) {
(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 = debug ? "//connect.facebook.net/en_US/all/debug.js" : "//connect.facebook.net/sv_SE/sdk.js";
fjs.parentNode.insertBefore(js, fjs);
}(document, 'script', 'facebook-jssdk'));
}
export default {
name: 'social-facebook',
initialize: initialize
};
{{social-facebook data-href="https://yourwebpage.com" data-layout="button_count" data-action="like" data-show-faces="false" data-share="true"}}