Tag Manager JS 上 dataLayer 推送事件的事件侦听器

Event listener for dataLayer push events on Tag Manager JS

我想添加一个自定义脚本以集成到页面上现有的跟踪代码管理器数据层中。我需要这个脚本来通知新的 dataLayer 推送。 因此,每当页面上的某些内容使用 window.dataLayer.push 时,我的脚本就应该被告知这一点。

有没有办法将自定义 dataLayer 事件侦听器添加到 Google 脚本 API?

我正在寻找类似

的东西
google_tag_manager.dataLayer.onPush(callback);

google_tag_manager.dataLayer.subscribers 似乎列出了有多少 dataLayer 订阅者 - 但我如何添加自己的订阅者?

我不确定您是否可以使用 google_tag_manager 对象执行 'native' 实现。但是,您可以覆盖 dataLayer 数组上的 push 方法。

const originalPush = dataLayer.push
dataLayer.push = function(...args) {
    // notify here
    console.log('dataLayer.push was called');
    
    originalPush(...args);
}

然后您可以根据 Observer Pattern.

实现一些逻辑

下面我展示了一个非常简单的实现,仅供演示。

const originalPush = dataLayer.push
const dataLayerListeners = [];
dataLayer.push = function(...args) {
    dataLayerListeners.forEach(listener => listener.notify())
    
    originalPush(...args);
}

class DatalayerListener {
    constructor(name) {
        this.name = name;
    }
    notify(args) {
        console.log("I'm listener "+this.name+" and I'm being notified that the dataLayer.push method was called");
    }
}

const listener1 = new DatalayerListener('listener1');
const listener2 = new DatalayerListener('listener2');

dataLayerListeners.push(listener1);
dataLayerListeners.push(listener2);

JavaScript 有一个 Proxy 对象,只要对对象执行操作,您就可以用它设置 traps。因为数组也是对象,所以可以用代理来实现。

在数组上调用push方法时,一个新值将set传给数组。因此,为 set 方法设置陷阱应该允许我们向 push 方法添加行为。

每当有东西被推送时,创建一个事件并发送它。现在,每当向 dataLayer 数组添加一个值时,都会发出一个事件。每当向 dataLayer 数组添加值时,您都可以从每个文件中侦听此事件以进行操作。

使用 Reflect 我们可以确保恢复 push 方法的原始行为,同时保持添加的行为。

window.dataLayer = window.dataLayer || new Proxy([], {
  set: (obj, prop, value) => {  
    if (prop !== 'length') {
      const pushEvent = new CustomEvent('datalayerpush', {
        detail: value
      });

      window.dispatchEvent(pushEvent);
    }
    
    return Reflect.set(obj, prop, value);
  }
});

window.addEventListener('datalayerpush', event => {
  console.log(`Value pushed to dataLayer: ${JSON.stringify(event.detail, null, 2)}`);
});

window.dataLayer.push({
  event: 'test'
});