我使用 Angular 2 作为前端构建了一个新网站。由于一切都是通过推动状态完成的,因此通常会触发 Google Analytics 代码向 Google 的服务器发送页面视图的页面加载操作已经不存在。
我该如何手动发送页面视图事件到 Google,以便跟踪我的网站用户正在查看什么?
我使用 Angular 2 作为前端构建了一个新网站。由于一切都是通过推动状态完成的,因此通常会触发 Google Analytics 代码向 Google 的服务器发送页面视图的页面加载操作已经不存在。
我该如何手动发送页面视图事件到 Google,以便跟踪我的网站用户正在查看什么?
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跟踪,并与其他分析供应商集成。
在 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且与先前发出的项不具有相同路由的项目。ga('set', 'page', event.urlAfterRedirects);
,然后再使用 ga('send', 'pageview');
。 - haitham<!-- 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});
});
}
}
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>
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;
};
this.router.events.subscribe(event => {
if (event instanceof NavigationEnd) {
ga('set','page', event.urlAfterRedirects);
ga('send', 'pageview');
}
});
let newRoute = this._router._location.path() || '/';
而不是let newRoute = this._location.path() || '/';
@IanBelcher - Tomer Almog并紧接着使用
ga('send', 'pageview')`。 - maxbellecfilter
在事件上而不是条件语句上会改善解决方案。 - schmijos