Ember-cli& Facebook分享按钮 - 怎么样?

时间:2015-01-14 23:52:28

标签: twitter ember.js facebook-javascript-sdk facebook-like ember-cli

目标 - 拥有Facebook的分享按钮

我遇到了各种各样的问题,我已经设法解决了大多数问题但从未同时解决过。

  • ReferenceError:未定义FB(控制台中的错误)
  • “FB init函数提供错误的版本错误”(控制台中的错误)
  • 转换到另一条路线后,我的按钮无法渲染。
  • 我的按钮呈现但是按钮周围没有与初始路线上相邻内容的间距

关于渲染问题( - /连字符是注意间距问题)

  • 第一次渲染:

1st render

  • 渲染第二个+时间:

2nd+ render

我学到了什么:

  • Facebook想要<div id="fb-root"></div>作为<body>
  • 中的第一个元素 可以在didInsertElement之后调用
  • FB.XFBML.parse()以在转换后呈现组件

我做了一个JSBin样板试验,它目前停留在一个未定义的FB错误。

部分答案我也感兴趣:

  • 了解解决方案的复杂程度至少必须达到一个好的结果(“它必须包含初始化程序,视图/组件!”或“你可以通过......来解决这个问题”。)

可能有用的零件

关于“在FB.init()之后”的帖子

初始化程序

/* global FB */
export default {
  name: 'facebook',

  initialize: function() {
    var fbAsyncInit = function() {
      FB.init({
        appId      : 123,
        xfbml      : true,
        version    : 'v2.2'
      });
    };

    (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";
       fjs.parentNode.insertBefore(js, fjs);
     }(document, 'script', 'facebook-jssdk'));

    window.fbAsyncInit = fbAsyncInit;
  }
};

组件

/* global FB */
import Ember from 'ember';

export default Ember.Component.extend({
    tagName: 'div',
    classNames: 'fb-like',
    attributeBindings: [
        'data-href',
        'data-layout',
        'data-action',
        'data-show-faces',
        'data-share'
    ],

    onDidInsertElement: function() {
        Ember.run.schedule('afterRender', FB.XFBML.parse);
    }.on('didInsertElement'),

    init: function() {
        Ember.run.schedule('afterRender', FB.XFBML.parse);
    }
});

脚本标记

<script type="text/javascript" src="//connect.facebook.net/en_US/sdk.js#xfbml=1&appId=123&version=v2.2"></script>

根div facebook要求

<div id="fb-root"></div>

1 个答案:

答案 0 :(得分:4)

加载Facebook SDK

import ENV from "my-app/config/environment";
import setupOfflineMode from "my-app/utils/offline-mode";

export function initialize(container, application) {
  // offline mode stubs `FB`
  if (ENV.offlineMode) { return setupOfflineMode(); }

  // 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();

  window.fbAsyncInit = fbAsyncInit;
}

function loadFacebookSDK() {
  (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";
    fjs.parentNode.insertBefore(js, fjs);
  }(document, 'script', 'facebook-jssdk'));
}

function initFacebook(FB) {
  FB.init({
    appId: ENV.FB_APP_ID,
    status: true,
    cookie: true,
    xfbml: true,
    version: ENV.GRAPH_API_VERSION
  });
}

export default {
  name: 'facebook',
  initialize: initialize
};

分享链接

认为这就是我需要做的一切;我希望我不会忘记一些事情......

我没有设置组件,所以这只是一个常规视图,但它应该可以正常工作。

  <div class="fb-share-button" {{bind-attr data-href=link}} data-type="button"></div>
export default Ember.View.extend({
  setupSocialNetworks: function() {
    Ember.run.scheduleOnce('afterRender', this, function() {
      FB.XFBML.parse();
    });
  }.on('didInsertElement')
});

更新:替代解决方案

我认为您使用的解决方案实际上取决于您的需求。我正专注于更快的首次渲染时间,因此我已将我的项目更改为{SDK} SDK deferReadiness

我一直在玩两种解决方案,我认为这完全取决于你的需求。

  1. 将Facebook SDK加载到初始化程序中,但设置全局访问承诺。

    这会在启动时启动加载,但允许您的应用程序继续启动而无需等待Facebook。所有对Facebook API的调用都需要通过诺言来访问。

    如果需要,我会分享这个细节,但现在我只关注下一个解决方案:

  2. 仅在服务中按需加载Facebook SDK。

    和以前一样,对Facebook API的所有访问都需要通过一个承诺,但这次它很好地封装在一个服务中,并且只按需加载:

  3. // app/services/facebook.js
    import Ember from 'ember';
    import ENV from "juniper/config/environment";
    
    var computed = Ember.computed;
    var RSVP = Ember.RSVP;
    
    var _facebookSDKDeferrable = Ember.RSVP.defer();
    
    var fbAsyncInit = function() {
      _initFacebook(window.FB);
      _facebookSDKDeferrable.resolve(window.FB);
    };
    
    window.fbAsyncInit = fbAsyncInit;
    
    export default Ember.Service.extend({
      // Resolves when the Facebook SDK is ready.
      //
      // Usage:
      //
      //     facebook: Ember.inject.service(),
      //     foo: function() {
      //       this.get('facebook.SDK').then(function(FB) {
      //         // Facebook SDK is ready and FB is a reference to the SDK
      //       });
      //     }
      SDK: computed.alias('FB'),
      FB: computed(function() {
        _loadFacebookSDK();
        return _facebookSDKDeferrable.promise;
      })
    
      // I've also put promisified helpers for Facebook SDK
      // methods here.
    });
    
    function _loadFacebookSDK() {
      (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";
        fjs.parentNode.insertBefore(js, fjs);
      }(document, 'script', 'facebook-jssdk'));
    
    }
    
    function _initFacebook(FB) {
      FB.init({
        appId: ENV.FB_APP_ID,
        status: true,
        cookie: true,
        xfbml: false,
        version: ENV.GRAPH_API_VERSION
      });
    }
    

    另请注意,我已将xfbml设置为false中的FB.init。如果在加载SDK之前已经呈现了您的共享链接,FB.init({ xfbml: true })将“解析”它们,并且您的FB.XFBML.parse()调用将再次执行此操作。通过将xfbml设置为false,您可以确保FB.XFBML.parse()只会被调用一次。