【问题标题】:What is the best approach to use Disqus in a single page application?在单页应用程序中使用 Disqus 的最佳方法是什么?
【发布时间】:2013-04-04 22:48:11
【问题描述】:

在单页应用程序中使用 Disqus 的最佳方法是什么? 我看到 angular js 文档已经成功实现了。

目前我们的方法在我们的 AngularJS 应用程序中看起来像这样,但它似乎不稳定,难以测试,并且加载了错误的线程 ID(几乎所有地方都加载了相同的线程)。

'use strict';

angular.module('studentportalenApp.components')
    .directive('disqusComponent',['$log', '$rootScope', function($log, $rootScope) {

    var _initDisqus = function _initDisqus(attrs)
    {
        if(window.DISQUS) {
            DISQUS.reset({
                reload: true,
                config: function () {
                    this.page.identifier = attrs.threadId;
                    this.disqus_container_id = 'disqus_thread';
                    this.page.url = attrs.permalinkUrl;
                }
            });
        }
        else
        {
            $log.error('window.DISQUS did not exist before directive was loaded.');
        }
    }

    //Destroy DISQUS bindings just before route change, to properly dispose of listeners and frame (postMessage nullpointer exception)
    $rootScope.$on('$routeChangeStart', function() {
            if(window.DISQUS) {
                DISQUS.reset();
            }           
    });


    var _linkFn = function link(scope, element, attrs) {
            _initDisqus(attrs);
        }


    return {
        replace: true,
        template: '<div id="disqus_thread"></div>',
        link: _linkFn
    };
}]);

【问题讨论】:

    标签: unit-testing angularjs disqus angularjs-directive single-page-application


    【解决方案1】:

    我还想在我的 AngularJS 驱动的博客中加入 Disqus。我发现现有的解决方案有点笨拙,所以我编写了自己的指令:

    .directive('dirDisqus', function($window) {
        return {
            restrict: 'E',
            scope: {
                disqus_shortname: '@disqusShortname',
                disqus_identifier: '@disqusIdentifier',
                disqus_title: '@disqusTitle',
                disqus_url: '@disqusUrl',
                disqus_category_id: '@disqusCategoryId',
                disqus_disable_mobile: '@disqusDisableMobile',
                readyToBind: "@"
            },
            template: '<div id="disqus_thread"></div><a href="http://disqus.com" class="dsq-brlink">comments powered by <span class="logo-disqus">Disqus</span></a>',
            link: function(scope) {
    
                scope.$watch("readyToBind", function(isReady) {
    
                    // If the directive has been called without the 'ready-to-bind' attribute, we
                    // set the default to "true" so that Disqus will be loaded straight away.
                    if ( !angular.isDefined( isReady ) ) {
                        isReady = "true";
                    }
                    if (scope.$eval(isReady)) {
                        // put the config variables into separate global vars so that the Disqus script can see them
                        $window.disqus_shortname = scope.disqus_shortname;
                        $window.disqus_identifier = scope.disqus_identifier;
                        $window.disqus_title = scope.disqus_title;
                        $window.disqus_url = scope.disqus_url;
                        $window.disqus_category_id = scope.disqus_category_id;
                        $window.disqus_disable_mobile = scope.disqus_disable_mobile;
    
                        // get the remote Disqus script and insert it into the DOM
                        var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;
                        dsq.src = '//' + scope.disqus_shortname + '.disqus.com/embed.js';
                        (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
                    }
                });
            }
        };
    });
    

    优势

    我认为这种方法的主要优点是它使事情变得简单。将指令注册到应用程序后,您无需编写任何 JavaScript 或在 JavaScript 中设置任何配置值。所有配置都通过在指令标签中传递属性来处理,如下所示:

    <dir-disqus disqus-shortname="YOUR_DISQUS_SHORTNAME"
        disqus-identifier="{{ article.id }}"
        disqus-title="{{ article.title }}"
        ...>
    </dir-disqus>
    

    此外,您无需更改 index.html 文件以包含 Disqus .js 文件 - 该指令将在准备好时动态加载它。这意味着所有额外的 .js 只会加载到那些实际使用 Disqus 指令的页面上。

    你可以看到完整的源代码和文档here on GitHub

    警告

    只有当您的网站处于 HTML5 模式时,上述内容才能正常工作,即不在您的网址中使用“#”。我正在更新 GitHub 上的代码,因此该指令在不使用 HTML5Mode 时将起作用,但请注意,您必须将 hashPrefix 设置为“!”制作“hashbang”网址 - 例如www.mysite.com/#!/page/123。这是 Disqus 施加的限制 - 请参阅 http://help.disqus.com/customer/portal/articles/472107-using-disqus-on-ajax-sites

    【讨论】:

    • 我怀疑这不是您的指令的问题,但无论如何,我的应用程序在每个带有评论部分的页面上呈现的每条评论。我将唯一标识符作为属性传递并使用 ng-bind-ready,因为我正在使用异步数据加载。我还检查了该指令,查看我的标识符。我正在使用没有 HTML5 模式且没有任何哈希前缀(只有 # 符号)的角度路由。您有任何解决方法的想法吗?我在你的指令 github 页面上添加了一个问题。
    • 好的,我们可以在 GitHub 问题跟踪器上继续此操作。对于任何有同样问题的阅读者,这里是链接:https://github.com/michaelbromley/angularUtils/issues/1
    • 显示错误:TypeError: Cannot read property 'disqus_shortname' of undefined
    【解决方案2】:

    我对 Disqus 一无所知,但根据 AngularJS 文档source code

    他们将加载函数绑定到 afterPartialLoaded:

    $scope.afterPartialLoaded = function() {
      var currentPageId = $location.path();
      $scope.partialTitle = $scope.currentPage.shortName;
      $window._gaq.push(['_trackPageview', currentPageId]);
      loadDisqus(currentPageId);
    };
    

    然后,他们只需将 html 添加到页面:

    function loadDisqus(currentPageId) {
      // http://docs.disqus.com/help/2/
      window.disqus_shortname = 'angularjs-next';
      window.disqus_identifier = currentPageId;
      window.disqus_url = 'http://docs.angularjs.org' + currentPageId;
    
      // http://docs.disqus.com/developers/universal/
      (function() {
        var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;
        dsq.src = 'http://angularjs.disqus.com/embed.js';
        (document.getElementsByTagName('head')[0] ||
          document.getElementsByTagName('body')[0]).appendChild(dsq);
      })();
    
      angular.element(document.getElementById('disqus_thread')).html('');
    }
    

    【讨论】:

      【解决方案3】:

      我们就是这样解决的。

      我们在 index.html 的主体中加载 DISQUS,并在有使用它的指令时重置它。

      指令:

      'use strict';
      
      angular.module('fooApp.directives')
          .directive('disqusComponent',['$window', '$log', function($window, $log) {
      
          var _initDisqus = function _initDisqus(scope)
          {
              if($window.DISQUS) {
                      $window.DISQUS.reset({
                          reload: true,
                          config: function () {
                              this.page.identifier = scope.threadId;
                              this.disqus_container_id = 'disqus_thread';
                          }
                      });
              }
              else
              {
                  $log.error('window.DISQUS did not exist before directive was loaded.');
              }
          }
      
          var _linkFn = function link(scope, element, attrs) {
                  element.html('<div id="disqus_thread"></div>');
                  _initDisqus(scope);
              }
      
      
          return {
              replace: true,
              template: 'false',
              scope: {
                  threadId: '@'
              },
              link: _linkFn
          };
      }]);
      

      这是如何测试的:

      'use strict';
      
      describe('Directive: Disqus', function() {
      
        var element, $window, $rootScope, $compile;
      
        beforeEach(function() {
          module('fooApp.directives', function($provide) {
              $provide.decorator('$window', function($delegate) {
      
                  $delegate.DISQUS = {
                      reset: jasmine.createSpy()
                  };
      
                  return $delegate;
              });
          });
      
          inject(function(_$rootScope_, _$compile_, _$window_) {
              $window = _$window_;
              $rootScope = _$rootScope_;
              $compile = _$compile_;
          });     
      
        });
      
      
        it('should place a div with id disqus_thread in DOM', function() {
          element = angular.element('<disqus-component></disqus-component>');
          element = $compile(element)($rootScope);
          expect(element.html()).toBe('<div id="disqus_thread"></div>');
        });
      
        it('should do a call to DISQUS.reset on load', function() {
          element = angular.element('<disqus-component thread-id="TESTTHREAD"></disqus-component>');
          element = $compile(element)($rootScope);
      
          var resetFn = $window.DISQUS.reset;
      
          expect(resetFn).toHaveBeenCalled();
        });
      
      });
      

      【讨论】:

      • 你确定 this.disqus_container_id 存在吗?文档中的任何地方都没有提到它。 this.disqus_category_id 也存在吗?不应该是 this.page.container_id 吗?
      猜你喜欢
      • 1970-01-01
      • 2018-05-24
      • 2017-11-24
      • 2011-01-21
      • 2011-11-20
      • 1970-01-01
      • 1970-01-01
      • 2021-08-03
      • 2010-09-12
      相关资源
      最近更新 更多