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 ?
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:
- comment sauvegarder un objet avec des références circulaires?
- Stringify (convertir en JSON) un objet JavaScript avec référence circulaire
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 :)
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;
}, ' ');
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));
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>
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.