【问题标题】:Ember-cli & Facebook-share buttons - how to?Ember-cli 和 Facebook 共享按钮 - 如何?
【发布时间】:2015-01-14 23:52:27
【问题描述】:

目标 - 为 Facebook 提供分享按钮

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

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

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

  • 第一次渲染:

  • 第二次以上渲染:

我学到了什么:

  • Facebook 希望<div id="fb-root"></div> 作为<body> 中的第一个元素
  • FB.XFBML.parse() 可以在 didInsertElement 之后调用以在过渡后渲染组件

我尝试了 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>

facebook 要求的根 div

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

【问题讨论】:

  • 我只是偶然发现了您的问题,因为我正在寻找相同的答案。您应该使您的 Initializer 异步,这可以确保在您的 Ember 应用程序启动之前定义全局 FB。这篇博文应该对您有所帮助:ember.zone/ember-application-initializers/…
  • 谢谢,它可能已经解决了一切!这也许可以解释为什么由于缓存等原因,第一次加载与第二次加载不同。据我测试,这解决了我的问题,但我总体上感到困惑。

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


【解决方案1】:

加载 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 的所有访问都需要通过一个 Promise,但这次它被很好地封装在一个服务中,并且只按需加载:

// 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 }) 将“解析”它们,而您的 FB.XFBML.parse() 调用将再次执行此操作。通过将xfbml 设置为false,您可以确保FB.XFBML.parse() 只会被调用一次。

【讨论】:

  • 是的,我认为解决问题的关键是在初始化程序中使用 deferReadiness / AdvanceReadiness!感谢您的回答!
  • 这与我使用的解决方案相同,但减去了脱机存根。很好的答案。
  • 顺便说一句,我认为您可以修剪 scheduleOnce 调用以直接调用 FB.XFBML.parse
猜你喜欢
  • 1970-01-01
  • 2014-07-28
  • 2011-06-22
  • 2015-01-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多