如果使用HTML5=true路由器,则Angularjs和change metatags支持不同视图的SEO

如果使用HTML5=true路由器,则Angularjs和change metatags支持不同视图的SEO,angularjs,Angularjs,我在客户端使用Angularjs,在服务器端使用dustjs&Nodejs,用于我基于SPA的站点。我需要在部分添加标记以支持SEO。我也在使用HTML5=true路由方法,因此我的URL没有#。由于我使用的是HTML5=true路由,因此我可以选择以下两个选项之一来实现搜索引擎优化 通过从视图控制器发出事件来更改元标记,并将其捕获到全局控制器中,然后更新元标记。下面的文章中提到了这种方法。 由于SEO将使用带有#的绝对URL,因此我可以使用dust.js+nodejs并根据URL更改元标记

我在客户端使用Angularjs,在服务器端使用dustjs&Nodejs,用于我基于SPA的站点。我需要在
部分添加
标记以支持SEO。我也在使用
HTML5=true
路由方法,因此我的URL没有#。由于我使用的是
HTML5=true
路由,因此我可以选择以下两个选项之一来实现搜索引擎优化

  • 通过从视图控制器发出事件来更改元标记,并将其捕获到全局控制器中,然后更新元标记。下面的文章中提到了这种方法。

  • 由于SEO将使用带有#的绝对URL,因此我可以使用dust.js+nodejs并根据URL更改元标记

  • 这两种方法都能满足我的要求,但我不确定哪一种是最好的。我正在考虑采用服务器端方法,即#2,因为它将简化我的代码,但不确定我将来会遇到什么问题

    请给我一些建议


    注意:我使用prerender.io为搜索引擎提供页面服务

    我在这方面有一些经验。 我的实现在客户端,我还使用了prerender.io

    根据我的经验-从变体#1开始(无论如何,为用户显示正确的标题是好的)。。。第一次(直到高负载,或者如果您可以缓存内容)。而且它很容易实现,并且在服务器和客户端之间没有逻辑复制

    但它也有缺点:prerender速度慢且不稳定(注意:我不是在prerender.io中谈论saas,而是关于我自己的服务器)

    因此,很可能以后您会决定将变体#2作为#1的补充或作为prerender的替代品来实现,但它更复杂,因为您需要在服务器端复制一些逻辑

    关于我的实施:

    我有一项服务,用于存储元标记信息:

    angular.module('....')
      .factory('seoParams', function ($rootScope) {
        var projectName = '....';
        var states = [];
        return {
          title: projectName,
          description: '',
          keywords: '',
          properties: {},
          canonical: false,
          prerenderStatusCode: 200,
    
          enter: function () {
            states.push({
              title: this.title,
              desctiption: this.desctiption,
              keyworwds: this.keyworwds,
              properties: this.properties,
              canonical: this.canonical,
              prerenderStatusCode: this.prerenderStatusCode
            });
    
            this.title = projectName;
            this.desctiption = '';
            this.keyworwds = '';
            this.properties = {};
            this.prerenderStatusCode = 200;
            this.canonical = false;
            return this;
          },
    
          exit: function () {
            var data = states.pop();
            _.assign(this, data);
          },
          setTitle: function (title) {
            this.title = title;
            return this;
          },
          setTitlePart: function (title) {
            this.title = title + ' ~ ' + projectName;
            return this;
          },
          setDescription: function (description) {
            this.description = description;
            return this;
          },
          setKeywords: function (keywords) {
            this.keywords = keywords;
            return this;
          },
          setCanonical: function (canonical) {
            this.canonical = canonical;
            return this;
          },
          setProperty: function (name, value) {
            this.properties[name] = value;
            return this;
          },
          appendProperties: function (properties) {
            _.assign(this.properties, properties);
            return this;
          },
          replaceProperties: function (properties) {
            this.properties = properties;
            return this;
          },
          setStatus: function (status) {
            this.prerenderStatusCode = status;
            return this;
          }
        };
      });
    
    要实际更新元标记的控制器:

    angular.module('....')
      .controller('SeoCtrl', function ($scope, seoParams, FB_APP_ID, TWITTER_SITE) {
        $scope.seoParams = seoParams;
        $scope.fbAppId = FB_APP_ID;
        $scope.twitterSite = TWITTER_SITE;
      });
    
    和视图:

    <head ng-controller="SeoCtrl">
      <base href="/"/>
      <title ng-bind="seoParams.title"></title>
      <meta property="fb:app_id" content="{{fbAppId}}">
      <meta ng-if="twitterSite" name="twitter:site" content="{{twitterSite}}">
      <meta name="description" content="{{seoParams.description}}">
      <meta name="keywords" content="{{seoParams.keywords}}">
      <meta
          ng-repeat="(property, content) in seoParams.properties"
          property="{{property}}"
          content="{{content}}"/>
      <meta name="prerender-status-code" content="{{seoParams.prerenderStatusCode}}">
      <link ng-if="seoParams.canonical" rel="canonical" href="{{seoParams.canonical}}" />
      <meta name="fragment" content="!">
      ...
    </head>
    
    如果需要,可以从控制器使用它,如下所示:

    seoParams.enter().setTitle(title)....
    $scope.$on('$destroy', function(){ seoParams.exit() });
    

    谢谢我忘记了哪些是与功能相关的。我现在将尝试客户端实现。@Bogdan Savluk我在哪里插入OneNet和onExit回调?谢谢在ui路由器中定义新状态时,它位于状态定义对象中。
    $stateProvider
    seoParams.enter().setTitle(title)....
    $scope.$on('$destroy', function(){ seoParams.exit() });