Comment stringify event object?

JSON.stringify(eventObject);

donne:

TypeError: Converting circular structure to JSON


dojox.json.ref.toJson(eventObject);

donne:

TypeError: Accessing selectionEnd on an input element that cannot have a selection.


y a-t-il une bibliothèque/un code prêt à être utilisé pour l'accomplir ?

21
demandé sur Tar 2012-07-18 22:08:30

5 réponses

vous ne pourrez pas sérialiser un objet event avec JSON.stringify, parce qu'un objet event contient des références à des noeuds DOM, et le DOM a des références circulaires partout (par exemple des relations enfant/parent). JSON ne peut pas les gérer par défaut, donc vous n'avez pas de chance là-bas.

je suggère de regarder comment sérialiser le noeud DOM à JSON même s'il y a des références circulaires? qui a quelques suggestions sur la façon de sérialiser un nœud DOM. En outre, les questions suivantes semblent avoir des informations utiles:

les bibliothèques JSON capables de traiter les références circulaires semblent être

alternativement, vous pouvez supprimer toutes les références aux noeuds DOM si vous n'en avez pas besoin, puis sérialiser l'objet. vous ne devriez pas faire ça après tout. Voir @PointedEars commentaire :)

15
répondu fresskoma 2017-05-23 10:29:54

utiliser la fonction" Remplacer "pour éviter les erreurs:

JSON.stringify(evt, function(k, v) {
    if (v instanceof Node) {
        return 'Node';
    }
    if (v instanceof Window) {
        return 'Window';
    }
    return v;
}, ' ');
5
répondu Alexander Shutov 2015-12-29 21:15:08

Je ne suis pas sûr que ça aide, mais je viens de tomber sur ceci dans la documentation angulaire de JS:

* Source: https://code.angularjs.org/1.5.5/docs/guide/expression#-event -

/*
 * return a copy of an object with only non-object keys
 * we need this to avoid circular references
 */
function simpleKeys (original) {
  return Object.keys(original).reduce(function (obj, key) {
    obj[key] = typeof original[key] === 'object' ? '{ ... }' : original[key];
    return obj;
  }, {});
}

Maintenant vous pouvez faire quelque chose comme:

JSON.stringify(simpleKeys(eventObject));
2
répondu bjunix 2016-05-17 08:47:38

j'ai eu un problème similaire et j'ai écrit un sérialiseur d'événement simple avec une méthode helper pour nettoyer l'attribut path de l'événement. L'approche pour cette solution de transformer des données de l'événement à un objet sérialisable:

  • copier sur les attributs primitifs
  • copier outerHTML pour les attributs d'élément dans l'objet d'événement
  • calculer le chemin du sélecteur pour l'attribut path (cela évite de copier l'enderhtml du toute la page HTML)

// Calculate a string representation of a node's DOM path.
var pathToSelector = function(node) {
  if (!node || !node.outerHTML) {
    return null;
  }

  var path;
  while (node.parentElement) {
    var name = node.localName;
    if (!name) break;
    name = name.toLowerCase();
    var parent = node.parentElement;

    var domSiblings = [];

    if (parent.children && parent.children.length > 0) {
      for (var i = 0; i < parent.children.length; i++) {
        var sibling = parent.children[i];
        if (sibling.localName && sibling.localName.toLowerCase) {
          if (sibling.localName.toLowerCase() === name) {
            domSiblings.push(sibling);
          }
        }
      }
    }

    if (domSiblings.length > 1) {
      name += ':eq(' + domSiblings.indexOf(node) + ')';
    }
    path = name + (path ? '>' + path : '');
    node = parent;
  }

  return path;
};

// Generate a JSON version of the event.
var serializeEvent = function(e) {
  if (e) {
    var o = {
      eventName: e.toString(),
      altKey: e.altKey,
      bubbles: e.bubbles,
      button: e.button,
      buttons: e.buttons,
      cancelBubble: e.cancelBubble,
      cancelable: e.cancelable,
      clientX: e.clientX,
      clientY: e.clientY,
      composed: e.composed,
      ctrlKey: e.ctrlKey,
      currentTarget: e.currentTarget ? e.currentTarget.outerHTML : null,
      defaultPrevented: e.defaultPrevented,
      detail: e.detail,
      eventPhase: e.eventPhase,
      fromElement: e.fromElement ? e.fromElement.outerHTML : null,
      isTrusted: e.isTrusted,
      layerX: e.layerX,
      layerY: e.layerY,
      metaKey: e.metaKey,
      movementX: e.movementX,
      movementY: e.movementY,
      offsetX: e.offsetX,
      offsetY: e.offsetY,
      pageX: e.pageX,
      pageY: e.pageY,
      path: pathToSelector(e.path && e.path.length ? e.path[0] : null),
      relatedTarget: e.relatedTarget ? e.relatedTarget.outerHTML : null,
      returnValue: e.returnValue,
      screenX: e.screenX,
      screenY: e.screenY,
      shiftKey: e.shiftKey,
      sourceCapabilities: e.sourceCapabilities ? e.sourceCapabilities.toString() : null,
      target: e.target ? e.target.outerHTML : null,
      timeStamp: e.timeStamp,
      toElement: e.toElement ? e.toElement.outerHTML : null,
      type: e.type,
      view: e.view ? e.view.toString() : null,
      which: e.which,
      x: e.x,
      y: e.y
    };

    console.log(JSON.stringify(o, null, 2));
  }
};

// Create a mock event for this example
var evt = new MouseEvent("click", {
  bubbles: true,
  cancelable: true,
  view: window
});
var cb = document.getElementById("clicker");

// Add a click listener
cb.addEventListener("click", serializeEvent);

// Fire the event
cb.dispatchEvent(evt);
<div>
  <button id="clicker" /> JSONify my click!
</div>
1
répondu y3sh 2017-02-16 22:07:21

donc, le problème est JSON.stringify semble renflouer dès qu'il trouve une référence circulaire. De toute façon, je n'étais pas intéressé par les propriétés référencées circulairement. La façon dont j'ai eu le reste d'entre eux est

var str = "{"
for (var key in data) {
  if (JSON.stringify(data[key]) !== "") {
    str += key + ":" + data[key]) + ",";
  }
}
str += "}"

cela vous donnera essentiellement le reste des propriétés. Pour éviter les erreurs JS vous pouvez mettre si dans try / catch.

0
répondu Saurabh 2018-02-12 10:13:09