Подтвердить что ты не робот

Каков наилучший подход к использованию Disqus в одностраничном приложении?

Каков наилучший подход к использованию Disqus в одностраничном приложении? Я вижу, что angular js docs успешно выполнил его.

В настоящее время наш подход выглядит так, как это в нашем приложении AngularJS, но он кажется нестабильным, его трудно проверить и загружает неправильные идентификаторы потоков (тот же поток загружается почти везде).

'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
    };
}]);
4b9b3361

Ответ 1

Я также хотел включить Disqus в мой блог с AngularJS. Я нашел существующие решения немного громоздкими, поэтому я написал свою собственную директиву:

.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.

Вы можете увидеть полный источник и документацию здесь, на GitHub

Caveat

Вышеуказанное будет работать только тогда, когда ваш сайт находится в HTML5Mode, т.е. не использует "#" в ваших URL-адресах. Я обновляю код на GitHub, поэтому директива будет работать, если вы не используете HTML5Mode, но будьте осторожны, вы должны установить hashPrefix из "!". для создания URL-адресов "hashbang" - например. www.mysite.com/#!/page/123. Это ограничение, наложенное Disqus - см. http://help.disqus.com/customer/portal/articles/472107-using-disqus-on-ajax-sites

Ответ 2

Я ничего не знаю о Disqus, но в соответствии с Документацией AngularJS исходный код:

Они связывают функцию загрузки с 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

Вот как мы его решили.

Мы загружаем DISQUS в тело index.html и сбрасываем его, когда есть директива, использующая его.

Директива

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

});