【问题标题】:Tracking Google Analytics Page Views in Angular2在 Angular2 中跟踪 Google Analytics 页面浏览量
【发布时间】:2016-06-06 11:10:28
【问题描述】:

我已经使用 Angular 2 作为前端构建了一个新站点。由于一切都是通过推送状态完成的,因此通常不会触发 Google Analytics 代码将页面视图发送到 Google 的服务器的页面加载。

如何手动向 Google 发送页面查看事件,以便跟踪我网站的用户正在查看哪些内容?

【问题讨论】:

    标签: javascript google-analytics angular


    【解决方案1】:

    我设法通过订阅路由器上的更改,检查路由是否确实发生了变化(有时我在某些路由上收到多个事件),然后将新路径发送给 Google,从而使这项工作正常进行。

    app.component.ts

    import { ... } from '...';
    
    // Declare ga function as ambient
    declare var ga:Function;
    
    @Component({ ... })
    
    export class AppComponent {
        private currentRoute:string;
    
        constructor(_router:Router) {
            // Using Rx's built in `distinctUntilChanged ` feature to handle url change c/o @dloomb's answer
            router.events.distinctUntilChanged((previous: any, current: any) => {
                // Subscribe to any `NavigationEnd` events where the url has changed
                if(current instanceof NavigationEnd) {
                    return previous.url === current.url;
                }
                return true;
            }).subscribe((x: any) => {
                ga('set', 'page', x.url);
                ga('send', 'pageview')
            });
          }
        }
    }
    

    在加载 angular2 应用程序之前,您还需要在主索引文件中包含谷歌分析代码,以便全局 ga 对象存在,但您不想发送两次初始视图。为此,请从 GA 脚本中删除以下行

    index.html

    <script>
      (function(i,s,o,g,r,a,m){...})(window,document,'script','https://www.google-analytics.com/analytics.js','ga');
    
      ga('create', 'UA-XXXXXXXX-X', 'auto');
      // Remove this line to avoid sending the first page view twice.
      //ga('send', 'pageview');
    
    </script>
    <!-- 
        Load your ng2 app after ga. 
        This style of deferred script loading doesn't guarantee this will happen
        but you can use Promise's or what works for your particular project. 
    -->
    <script defer type="text/javascript" src="/app.js"></script>
    

    使用第三方库

    作为自己实施 GA 的替代方案,库 Angulartics2 也是实施 GA 跟踪的流行工具,并且还与其他分析供应商集成。

    【讨论】:

    • 有没有办法避免在 index.html 中添加内联脚本?我认为 Angular js 背后的重点是保持 JS 脚本井井有条。
    • Angular2 本身不组织脚本,但它确实适用于更新样式的脚本加载,例如 amd 和 commonjs 等。加载 GA 的方式取决于您的加载器,以及它是否适用于全局声明的脚本,例如作为嘎。这个答案几乎是一种“一刀切”的方法。
    • 我认为应该是let newRoute = this._router._location.path() || '/'; 而不是let newRoute = this._location.path() || '/'; @IanBelcher
    • 根据developers.google.com/analytics/devguides/collection/…,你应该ga('set', 'page', newRoute)然后ga('send', 'pageview')
    • 在 Visual Basic 代码中出现了一些错误:'(event: Event) => void 类型的参数不可分配给'(value: Event) => void' 类型的参数。参数 'event' 和 'value' 的类型不兼容。类型“事件”不可分配给类型“事件”。存在具有此名称的两种不同类型,但它们不相关。类型“NavigationStart”不可分配给类型“事件”。 “NavigationStart”类型中缺少属性“bubbles”。
    【解决方案2】:

    如果您在 2017 年 8 月之后遇到此问题,那么您很可能应该使用 gtag.js(Google Universal Analytics 全球网站标签)而不是旧的 analytics.js。我建议您在继续之前检查Migrate from analytics.js to gtag.js 页面和How gtag.js works in Single page applications 两者之间的区别。

    当您从 Google Analytics 获取代码 sn-p 时,它看起来像这样:

    <!-- Global site tag (gtag.js) - Google Analytics -->
    <script async src="https://www.googletagmanager.com/gtag/js?id=<%= GOOGLE_ANALYTICS_ID %>"></script>
    <script>
      window.dataLayer = window.dataLayer || [];
      function gtag(){dataLayer.push(arguments);}
      gtag('js', new Date());
    
      gtag('config', '<%= GOOGLE_ANALYTICS_ID %>'); <!-- Remove that one -->
    </script>
    

    您需要删除脚本的最后一行并将其余部分添加到您的index.html

    然后您必须将从上面的脚本中删除的行添加到您的代码中并添加要跟踪的页面。基本上它与上面建议的analytics.js 几乎相同,但现在您使用gtag.js 函数。

    例如,如果你想跟踪你打开的所有页面,这里是示例代码:

    import { Component, OnInit } from '@angular/core';
    import { Router, NavigationEnd } from '@angular/router';
    import 'rxjs/add/operator/distinctUntilChanged';
    
    // This still has to be declared
    declare var gtag: Function;
    
    @Component({
        moduleId: module.id,
        selector: 'my-app',
        templateUrl: 'app.component.html',
        styleUrls: ['app.component.css'],
    })
    export class AppComponent implements OnInit {
    
        constructor(private router: Router) { }
    
        ngOnInit() {
            this.router.events.distinctUntilChanged((previous: any, current: any) => {
                // Subscribe to any `NavigationEnd` events where the url has changed
                if(current instanceof NavigationEnd) {
                    return previous.url === current.url;
                }
                return true;
            }).subscribe((x: any) => {
                gtag('config', '<%= GOOGLE_ANALYTICS_ID %>', {'page_path': x.url});
            });
        }
    }
    

    如果您已阅读 gtag.js 的文档,那么您就会知道可能有很多跟踪选项,但我在这里只关注最基本的用法。

    【讨论】:

      【解决方案3】:

      在 Angular 6 中,我建议使用 app.component.ts:

      import { Component, OnInit } from '@angular/core';
      import { Router, NavigationEnd } from '@angular/router'
      import { Title } from '@angular/platform-browser';
      
      @Component({
        selector: 'app-root',
        templateUrl: './app.component.html',
        styleUrls: ['./app.component.css']
      })
      
      export class AppComponent {
      
        constructor(
          private router: Router,
          private titleService: Title
        ){ }
      
        ngOnInit() {
           this.router.events.subscribe(event => {
            if (event instanceof NavigationEnd) {
              (<any>window).gtag('config', '<%= GOOGLE_ANALYTICS_ID %>', {
                'page_title' : this.titleService.getTitle(),
                'page_path': event.urlAfterRedirects
              });
            }
          });
        }
      
      }
      

      对于 index.html :

        <!-- Global site tag (gtag.js) - Google Analytics -->
        <script async src="https://www.googletagmanager.com/gtag/js?id=<%= GOOGLE_ANALYTICS_ID %>"></script>
        <script>
          window.dataLayer = window.dataLayer || [];
          function gtag() { dataLayer.push(arguments); }
          gtag('js', new Date());
        </script>
      

      您可以使用 Angular 提供的 Title 服务来管理页面的标题:https://angular.io/guide/set-document-title

      【讨论】:

        【解决方案4】:

        扩展伊恩的答案。您可以使用 Rx 的内置功能来处理当前路由和新路由之间的区别。

        import { NavigationEnd, Router } from '@angular/router';
        
        declare var ga: any;
        
        export class AppComponent {
                constructor(public router: Router) {
                    router.events.distinctUntilChanged((previous: any, current: any) => {
                        if(current instanceof NavigationEnd) {
                            return previous.url === current.url;
                        }
                        return true;
                    }).subscribe((x: any) => {
                        console.log('router.change', x);
                        ga('send', 'pageview', x.url);
                    });
                }
            }
        

        我们使用 distinctUntilChanged 操作符让观察者只发射 NavigationEnd 类型的项目,并且与之前发射的项目不具有相同的路由。

        【讨论】:

        • 我得到了一个 wright console.log(),但在控制台中我看不到 ga('send', 'pageview');添加到我的分析脚本中。这正常吗?
        • 你应该先ga('set', 'page', event.urlAfterRedirects); 然后ga('send', 'pageview');
        • 看到一些错误:'(event: Event) => void' 类型的参数不可分配给'(value: Event) => void' 类型的参数。参数 'event' 和 'value' 的类型不兼容。类型“事件”不可分配给类型“事件”。存在同名的两种不同类型,但它们不相关。
        【解决方案5】:
        this.router.events.subscribe(event => {
            if (event instanceof NavigationEnd) {
                ga('set','page', event.urlAfterRedirects);
                ga('send', 'pageview');
            }
        });
        

        【讨论】:

        • 新的简单方法
        【解决方案6】:

        假设每个 Angular Route 在app.routing.ts 中都有自己的标题:

           {
            path: 'shop',
            component: ShopComponent,
            data: {
              title: ' == This is Shop Component Title =='
            },
            canActivate: [AuthGuard]
          },
        

        前面提到的解决方案仍会在 Google Analytics(分析)报告中为每条路线显示相同的页面标题。为了使用相应的 Angular Route 标题(而不是 index.html &lt;title&gt; 的标签内容),请在app.component.ts 中使用下面的代码

          this.router.events.subscribe(event => {
        
          if (event instanceof NavigationEnd) {
            (<any>window).ga('set', 'page', event.urlAfterRedirects);
        
            // ----------
            //use the following 3 lines of code to use
            //correnct titles for routes        
            // ----------
        
            let currentRoute = this.route.root;
            let title = this.getPageTitle(currentRoute);
            (<any>window).ga('set', 'title', title);
        
            (<any>window).ga('send', 'pageview');
        
          }
        });
        

        ...其中getPageTitle方法如下:

        getPageTitle = function (currentRoute: ActivatedRoute) {
          let data;
            do {
              const childrenRoutes = currentRoute.children;
              currentRoute = null;
              childrenRoutes.forEach(route => {
        
              if (route.outlet === 'primary') {
                currentRoute = route;
                data = route.snapshot.data;
              }
            });
          } while (currentRoute);
          return data.title;
        };
        

        注意:此解决方案适用于 Anguler 5 及以下版本。在 Angular 6 中,你也可以使用TitleService

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多