Analytics

Suivre les interactions dans le Shadow DOM à l’aide de Google Tag Manager

Les DOM fantôme est un moyen d’ajouter des structures HTML à la page Web afin qu’elles restent isolées du reste du modèle d’objet de document (DOM). C’est un concept populaire avec les composants Web, car il permet de encapsulation des structures Web afin qu’elles ne soient pas affectées par les déclarations de style de l’arbre parent, par exemple.

DOM fantôme

Cependant, étant une telle structure “cachée”, tout ce qui se passe dans le DOM fantôme est également caché aux auditeurs de Google Tag Manager. Ou le clic Est-ce que s’inscrire, mais la cible de l’événement ({{Cliquez sur l’élément}}) est le nœud de la structure parent qui hôtes le shadow DOM plutôt que l’élément sur lequel on a cliqué dans le DOM fantôme.

DOM fantôme cliqué

Dans cet exemple, GTM remplirait les variables de clic afin que le clic semble atterrir sur le <div class="postShorten-wrap"> quand il a effectivement atterri sur l’élément à l’intérieur #shadow-root. De même, étant donné que le contenu du DOM fantôme est masqué de la structure parente, le prédicat du sélecteur CSS matches ne peut pas être utilisé pour voir ce qui se trouve à l’intérieur de l’élément cliqué.

Nous pouvons contourner cela ! Nous ne pouvons pas utiliser les déclencheurs intégrés de GTM car ils ne nous permettent pas d’accéder au event objet lui-même. Mais nous pouvons utiliser un écouteur d’événement personnalisé.

Pour plus de détails sur le fonctionnement de la gestion des événements dans le DOM fantôme, consultez cet excellent article sur le sujet.

Fonctionnement de la gestion des événements avec le DOM fantôme

Les écouteurs d’événements dans le DOM fantôme fonctionnent exactement comme les écouteurs d’événements sur les structures DOM normales. Un événement est enregistré et il remplit un chemin à travers les couches du site pendant la capture et bubble phases.

Certains événements remontent vers le haut de l’arborescence DOM, d’autres restent sur le nœud où l’événement a été enregistré.

La principale différence avec le DOM fantôme est que les événements qui commencent à remonter ne traversent la limite du DOM fantôme que s’ils ont la propriété composed mis à true.

La plupart des événements ont composed mis à true. Généralement, les exceptions sont des événements qui ne sont pas basés sur les interactions de l’interface utilisateur. Comme ceux-ci:

  • load
  • unload
  • abort
  • error

Pour les événements qui ont composed mis à truenous pouvons attacher un écouteur d’événement personnalisé sur le document node, par exemple, et les événements qui ont lieu dans le shadow DOM se propageront à notre écouteur (en supposant qu’ils bulleou l’écouteur a été réglé pour détecter le Capturer phase à la place).

Cependant, nous sommes toujours confrontés au problème introduit au début de cet article. Tous les événements qui ont lieu dans le shadow DOM sont automatiquement délégués au parent du #shadow-root. Ce n’est pas très utile. Le DOM fantôme pourrait être une chose énorme et tentaculaire, nous avons donc besoin précision.

Heureusement, nous pouvons utiliser le Event.composedPath() méthode pour obtenir un tableau qui représente la chemin l’événement a pris comme il bouillonnait. Le tout premier membre du tableau est l’élément qui a été réellement cliqué (sauf si le shadow DOM a été closedmais nous y reviendrons dans une minute).

Nous pouvons utiliser ces informations pour construire notre auditeur.

L’auditeur

Dans Google Tag Manager, créez un Balise HTML personnaliséepuis saisissez ou copiez-collez le code suivant.

<script>   (function() {     // Set to the event you want to track     var eventName = 'click',     // Set to false if you don't want to use capture phase         useCapture = true,     // Set to false if you want to track all events and not just those in shadow DOM         trackOnlyShadowDom = true;      var callback = function(event) {       if ('composed' in event && typeof event.composedPath === 'function') {         // Get the path of elements the event climbed through, e.g.         // [span, div, div, section, body]         var path = event.composedPath();                  // Fetch reference to the element that was actually clicked         var targetElement = path[0];                  // Check if the element is WITHIN the shadow DOM (ignoring the root)         var shadowFound = path.length ? path.filter(function(i) {           return !targetElement.shadowRoot && !!i.shadowRoot;         }).length > 0 : false;                  // If only shadow DOM events should be tracked and the element is not within one, return         if (trackOnlyShadowDom && !shadowFound) return;                  // Push to dataLayer         window.dataLayer.push({           event: 'custom_event_' + event.type,           custom_event: {             element: targetElement,             elementId: targetElement.id || '',             elementClasses: targetElement.className || '',             elementUrl: targetElement.href || targetElement.action || '',             elementTarget: targetElement.target || '',             originalEvent: event,             inShadowDom: shadowFound           }         });       }     };          document.addEventListener(eventName, callback, useCapture);   })(); </script>

Vous pouvez joindre un Affichage des pages déclencheur à cette balise. Après cela, chaque clic sur les pages où l’auditeur est actif sera poussé dans dataLayer avec un contenu d’objet qui ressemble à ceci :

Objet de la couche de données

Dans ce cas, le clic est tombé sur un <div> avec très peu d’attributs, mais qui était contenu dans l’ombre Dom (comme isShadowDom est true).

Vous pouvez ensuite créer un déclencheur d’événement personnalisé pour custom_event_click:

Déclencheur d'événement personnalisé

Et vous pouvez créer des variables de couche de données pour les éléments individuels dans l’objet poussé comme ceci :

Variable de couche de données

En commutant eventName dire, submitvous pouvez écouter les soumissions de formulaire à la place.

Si vous voulez éviter que le script envoie un message avec chaque instance d’événement, vous pouvez ajouter des vérifications dans le rappel pour vérifier que la cible de l’événement était un type d’élément spécifique. Par exemple, pour pousser vers dataLayer uniquement si le clic a atterri sur un lien, vous pouvez faire quelque chose comme ceci :

var callback = function(event) {   ...   var targetElement = path[0];   if (targetElement.matches('a, a *')) {     // Run the dataLayer.push() here   }   ... ...

Note! Bien que ce ne soit qu’un exemple, vous devez savoir que .matches() ne fonctionnera pas dans IE, et vous devrez utiliser .msMatchesSelector().

Qu’en est-il des événements non composés ?

Et si vous voulez suivre des événements qui n’ont pas le composed drapeau défini sur true? Si vous vous en souvenez, ces événements ne se propageront pas au-delà des limites du DOM fantôme. De même, si vous utilisez le script ci-dessus, ils auront également le inShadowDom drapeau défini sur falsecar ils sont pratiquement inconscients du fait qu’ils se trouvent dans un DOM fantôme (style Matrix).

Ainsi, vous devrez gérer les événements sans pouvoir de délégation. En d’autres termes, vous devrez ajouter les écouteurs directement aux éléments.

Par exemple, si vous vouliez suivre un load événement pour un <script> dans le shadow DOM, le script ressemblerait à ceci :

<script>   (function() {     // Set to the event you want to track     var eventName = 'load';     // useCapture is irrelevant as we'll be tracking the element itself     //  useCapture = true,     // trackOnlyShadowDom is irrelevant as we'll be only tracking an element in the shadow DOM     //  trackOnlyShadowDom = true;      var callback = function(event) {       if ('composed' in event && typeof event.composedPath === 'function') {         // Irrelevant in this solution, as we are tracking the element itself         // var path = event.composedPath();                  // Irrelevant.         // var targetElement = path[0];                  var targetElement = event.target;                  // Irrelevant.         // var shadowFound = path.length ? path.filter(function(i) {         //   return !targetElement.shadowRoot && !!i.shadowRoot;         // }).length > 0 : false;                  // Irrelevant         // if (trackOnlyShadowDom && !shadowFound) return;                  // Push to dataLayer         window.dataLayer.push({           event: 'custom_event_' + event.type,           custom_event: {             element: targetElement,             elementId: targetElement.id || '',             elementClasses: targetElement.className || '',             elementUrl: targetElement.href || targetElement.action || '',             elementTarget: targetElement.target || '',             originalEvent: event,             inShadowDom: true           }         });       }     };          // This is where the script sets the listener on the actual element in the shadow root     // The script checks if the container exists in the standard DOM, then it checks if the container     // is the shadow root, and finally it checks if the shadow DOM has the script element.     var shadowContainer = document.querySelector('.shadowDomContainer');     if (!!shadowContainer && !!shadowContainer.shadowRoot) {       var scriptTarget = shadowContainer.shadowRoot.querySelector('script#someId');       if (!!scriptTarget) scriptTarget.addEventListener(eventName, callback);     }   })(); </script>

Ici le addEventListener call à la fin est un peu plus complexe que le générique que nous avons utilisé auparavant. Vous devez d’abord trouver le nœud auquel le DOM fantôme est intégré (le racine de l’ombre). Ensuite, en accédant à son shadowRoot propriété, vous êtes autorisé à rechercher des éléments dans le DOM fantôme (en supposant que le DOM fantôme est open).

Après les vérifications habituelles pour savoir si l’élément existe, vous pouvez ensuite ajouter votre écouteur directement à l’élément, et il invoquera le rappel dès qu’il enregistrera l’événement.

Qu’en est-il d’un DOM fantôme fermé ?

Si le DOM fantôme est créé dans closed mode, vous êtes fondamentalement incapable de faire quoi que ce soit avec le shadowRoot. Si vous essayez d’y accéder avec les méthodes DOM, le shadowRoot la propriété reviendra simplement nullet de même le composedPath() renvoie un tableau d’éléments qui s’arrête au nœud racine fantôme.

Ainsi, à un niveau superficiel, vous ne pouvez vraiment rien faire pour suivre les interactions précises au sein du DOM fantôme.

Cependant, il existe une solution de contournement.

Lorsque le DOM fantôme est créé, si les développeurs stockent une référence à celui-ci dans une variable globale, vous pouvez interagir avec lui et vous pouvez ajouter des écouteurs aux éléments du fragment de document si vous le souhaitez.

// Create a shadow DOM var container = document.querySelector('.someContainer'); window._shadowRoot = container.attachShadow({mode: 'closed'}); 

Dans l’exemple ci-dessus, la variable globale _shadowRoot maintient une référence au DOM fantôme, et vous pouvez donc utiliser des méthodes telles que window._shadowRoot.addEventListener(...) pour manipuler et interagir avec des éléments dans le shadow DOM.

Cela nécessite une certaine coopération avec les développeurs, et vous devez également justifier pourquoi le mode est défini sur closed en premier lieu si les développeurs ajoutent une ouverture par le biais d’une variable globale.

Résumé

Espérons que cet article a été instructif. J’ai l’intuition que le shadow DOM est un peu un mystère pour de nombreux développeurs d’analyses Web simplement parce que ce n’est pas le moyen le plus courant d’ajouter des éléments à la page Web.

Cependant, il offre des outils puissants pour l’encapsulation et la séparation des préoccupations, et en particulier au lieu d’intégrations iframe maladroites, cela pourrait avoir beaucoup de sens du point de vue du développement Web.

Les pointeurs de cet article devraient vous donner les outils pour identifier un autre problème potentiel avec les écouteurs intégrés de Google Tag Manager, et cela devrait vous aider à le résoudre avec la puissance de certains scripts personnalisés.

Source : www.simoahava.com

Articles similaires

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Bouton retour en haut de la page
Index