在Angular2中跟踪Google Analytics页面浏览量

50

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

我该如何手动发送页面视图事件到 Google,以便跟踪我的网站用户正在查看什么?

6个回答

59
我通过订阅路由的更改状态,检查路由是否实际更改(有时候某些路由会收到多个事件),然后将新的路径发送给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.pipe(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应用程序之前,您还需要将Google Analytics代码包含在主索引文件中,以便全局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跟踪,并与其他分析供应商集成。


Angular2本身不会组织脚本,但它可以与较新的脚本加载方式(如amd和commonjs等)一起使用。如何加载GA取决于您的加载器以及它是否与全局声明的脚本(如ga)一起使用。这个答案基本上是“一刀切”的方法。 - Ian Belcher
1
我认为应该是 let newRoute = this._router._location.path() || '/'; 而不是 let newRoute = this._location.path() || '/'; @IanBelcher - Tomer Almog
5
根据https://developers.google.com/analytics/devguides/collection/analyticsjs/single-page-applications的说明,您应该使用`ga('set', 'page', newRoute)并紧接着使用ga('send', 'pageview')`。 - maxbellec
1
在 Visual Basic 代码中遇到了一些错误:'Argument of type '(event: Event) => void' is not assignable to parameter of type '(value: Event) => void'. Types of parameters 'event' and 'value' are incompatible. Type 'Event' is not assignable to type 'Event'. Two different types with this name exist, but they are unrelated. Type 'NavigationStart' is not assignable to type 'Event'. Property 'bubbles' is missing in type 'NavigationStart'.' - etayluz
使用 filter 在事件上而不是条件语句上会改善解决方案。 - schmijos
显示剩余2条评论

33

在 Ian 的回答基础上拓展。你可以使用 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且与先前发出的项不具有相同路由的项目。

我得到了正确的console.log(),但在控制台中我看不到添加到我的分析脚本的ga('send','pageview')。这正常吗? - Bas
2
你应该先使用 ga('set', 'page', event.urlAfterRedirects);,然后再使用 ga('send', 'pageview'); - haitham
看到一些错误:'类型为'(event: Event) => void'的参数无法分配给类型为'(value: Event) => void'的参数。 事件和值的类型不兼容。 类型“Event”不能分配给类型“Event”。存在两个名称相同但不相关的不同类型。 - etayluz

24
如果您在2017年8月之后遇到此问题,则最有可能应该使用gtag.js(Google通用分析全局站点标记)而不是旧的analytics.js。 我建议您在继续之前查看从analytics.js迁移到gtag.js页面以及gtag.js在单页应用程序中的工作方式之间的区别。
当您从Google Analytics获取代码片段时,它看起来像这样:
<!-- 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});
        });
    }
}

如果您已经阅读了的文档,那么您就知道可能有大量的跟踪选项,但是我在这里专注于最基本的用法。

6
在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

0
假设每个 Angular 路由在 app.routing.ts 中都有自己的标题:
   {
    path: 'shop',
    component: ShopComponent,
    data: {
      title: ' == This is Shop Component Title =='
    },
    canActivate: [AuthGuard]
  },

之前提到的解决方案仍会在Google Analytics报告中为每个路由显示相同的页面标题。为了使用相应的Angular路由标题(而不是始终使用index.html中的<title>标签内容),请在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;
};

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

-1
this.router.events.subscribe(event => {
    if (event instanceof NavigationEnd) {
        ga('set','page', event.urlAfterRedirects);
        ga('send', 'pageview');
    }
});

新的简单方式 - Tony Muchui Blaxx

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接