FB.XFBML.parse()找不到Ember组件呈现的HTML

时间:2015-03-19 16:21:38

标签: ember.js facebook-javascript-sdk

更新1

我已经将问题追溯到FB.XFBML.parse()使用的html5Info函数。它有条件。这是两个元素不同的布尔语句:element.getAttribute('fb-xfbml-state')变为"rendered"(truthy)或null(falsy),具体取决于处理的元素。

所以问题缩小到......

为什么我的ember-component的呈现HTML没有将'fb-xfbml-state'设置为“呈现”而模板中的静态HTML有?

更新2

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'),
});

更新3

组件似乎生成子节点,如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一样?

我的路由模板生成相同的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中显示以下内容:

Identical HTML output - Yet the FB.XFBML.parse() command seem to make a difference on them, no matter what order I put them in also

我的组件

/* 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
};

1 个答案:

答案 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"}}