Ember-cli & Facebook-share 按钮 - 如何?

Ember-cli & Facebook-share buttons - how to?

目标 - 拥有 Facebook 的分享按钮

我遇到过各种各样的问题,我设法解决了大部分问题,但从来没有同时解决过所有问题。

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

我学到了什么:

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

我也感兴趣的部分答案:

可能有用的部分

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

一个初始化程序

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

root div facebook 请求

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

正在加载 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')
});

更新:替代解决方案

我认为您使用哪种解决方案完全取决于您的需求。我专注于缩短首次渲染时间,因此我已将我的项目更改为不针对 Facebook SDK deferReadiness

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

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

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

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

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

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

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

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