javascript 如何字符串化事件对象?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/11547672/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to stringify event object?
提问by Tar
JSON.stringify(eventObject);
JSON.stringify(eventObject);
gives:
给出:
TypeError: Converting circular structure to JSON
TypeError: Converting circular structure to JSON
dojox.json.ref.toJson(eventObject);
dojox.json.ref.toJson(eventObject);
gives:
给出:
TypeError: Accessing selectionEnd on an input element that cannot have a selection.
TypeError: Accessing selectionEnd on an input element that cannot have a selection.
Is there some library/code ready to use to accomplish it ?
是否有一些库/代码可以用来完成它?
采纳答案by fresskoma
You won't be able to serialize an event object with JSON.stringify, because an event object contains references to DOM nodes, and the DOM has circular references all over the place (e.g. child/parent relationships). JSON can't handle these by default, so you're a bit out of luck there.
您将无法使用 JSON.stringify 序列化事件对象,因为事件对象包含对 DOM 节点的引用,并且 DOM 到处都有循环引用(例如子/父关系)。默认情况下 JSON 不能处理这些,所以你在那里有点不走运。
I'd suggest to look at How to serialize DOM node to JSON even if there are circular references?which has a few suggestions on how to serialize a DOM node. Also, the following questions seem to have useful information:
我建议查看如何将 DOM 节点序列化为 JSON 即使有循环引用?其中有一些关于如何序列化 DOM 节点的建议。此外,以下问题似乎有有用的信息:
- How to save an object with circular references?
- Stringify (convert to JSON) a JavaScript object with circular reference
JSON libraries able to handle circular references seem to be
能够处理循环引用的 JSON 库似乎是
Alternatively, you could delete all references to DOM nodes if you don't need them, and then serialize the object.You shouldn't do this after all. See @PointedEars comment :)
或者,如果不需要它们,您可以删除对 DOM 节点的所有引用,然后序列化对象。毕竟你不应该这样做。见@PointedEars 评论:)
回答by Alexander Shutau
Use the "replacer" function to avoid errors:
使用“替换器”功能避免错误:
JSON.stringify(evt, function(k, v) {
if (v instanceof Node) {
return 'Node';
}
if (v instanceof Window) {
return 'Window';
}
return v;
}, ' ');
Update 2019:the browser API has changed some way, here is a method to expose all available keys in Event prototype chain
2019 年更新:浏览器 API 发生了一些变化,这里是一种公开事件原型链中所有可用键的方法
function stringifyEvent(e) {
const obj = {};
for (let k in e) {
obj[k] = e[k];
}
return JSON.stringify(obj, (k, v) => {
if (v instanceof Node) return 'Node';
if (v instanceof Window) return 'Window';
return v;
}, ' ');
}
回答by y3sh
I had a similar problem and wrote a simple event serializer with a helper method to cleanup the event's path attribute. The approach for this solution to transform data from the event to a serializable object:
我遇到了类似的问题,并编写了一个简单的事件序列化程序,其中包含一个辅助方法来清理事件的路径属性。此解决方案将数据从事件转换为可序列化对象的方法:
- Copy over primitive attributes
- Copy outerHTML for element attributes in the event object
- Calculate selector path for the path attribute (this avoids copying the outerHTML of the entire HTML page)
- 复制原始属性
- 复制事件对象中元素属性的外层HTML
- 计算path属性的选择器路径(这样可以避免复制整个HTML页面的outerHTML)
// 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>
回答by bjunix
Not sure if it helps, but I just stumbled upon this in the Angular JS documentation:
不确定它是否有帮助,但我只是在 Angular JS 文档中偶然发现了这一点:
*Source: https://code.angularjs.org/1.5.5/docs/guide/expression#-event-
*来源: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;
}, {});
}
Now you could do something like:
现在您可以执行以下操作:
JSON.stringify(simpleKeys(eventObject));
回答by Octo Poulos
Improved version of the code given by Alexander Shutau, as this one handles multi level objects (ES6):
Alexander Shutau 给出的代码的改进版本,因为这个版本处理多级对象(ES6):
function stringify_object(object, depth=0, max_depth=2) {
// change max_depth to see more levels, for a touch event, 2 is good
if (depth > max_depth)
return 'Object';
const obj = {};
for (let key in object) {
let value = object[key];
if (value instanceof Node)
// specify which properties you want to see from the node
value = {id: value.id};
else if (value instanceof Window)
value = 'Window';
else if (value instanceof Object)
value = stringify_object(value, depth+1, max_depth);
obj[key] = value;
}
return depth? obj: JSON.stringify(obj);
}
Just call it like this:
就这样称呼它:
stringify_object(event, 2);
For example, on a touchstart event, I'm getting this:
例如,在 touchstart 事件中,我得到以下信息:
touchstart : {"isTrusted":true,"touches":{"0":{"identifier":0,"target":{"id":"screen"},"screenX":548,"screenY":281.5,"clientX":498.1817932128906,"clientY":185.90908813476562,"pageX":498.1817932128906,"pageY":185.90908813476562,"radiusX":29.77272605895996,"radiusY":27.954544067382812,"rotationAngle":0,"force":0.5},"length":1,"item":{}},"targetTouches":{"0":{"identifier":0,"target":{"id":"screen"},"screenX":548,"screenY":281.5,"clientX":498.1817932128906,"clientY":185.90908813476562,"pageX":498.1817932128906,"pageY":185.90908813476562,"radiusX":29.77272605895996,"radiusY":27.954544067382812,"rotationAngle":0,"force":0.5},"length":1,"item":{}},"changedTouches":{"0":{"identifier":0,"target":{"id":"screen"},"screenX":548,"screenY":281.5,"clientX":498.1817932128906,"clientY":185.90908813476562,"pageX":498.1817932128906,"pageY":185.90908813476562,"radiusX":29.77272605895996,"radiusY":27.954544067382812,"rotationAngle":0,"force":0.5},"length":1,"item":{}},"altKey":false,"metaKey":false,"ctrlKey":false,"shiftKey":false,"view":"Window","detail":0,"sourceCapabilities":{"firesTouchEvents":true},"which":0,"initUIEvent":{},"NONE":0,"CAPTURING_PHASE":1,"AT_TARGET":2,"BUBBLING_PHASE":3,"type":"touchstart","target":{"id":"screen"},"currentTarget":{"id":"screen"},"eventPhase":2,"bubbles":true,"cancelable":true,"defaultPrevented":false,"composed":true,"timeStamp":192516.7899999651,"srcElement":{"id":"screen"},"returnValue":true,"cancelBubble":false,"path":{"0":{"id":"screen"},"1":{"id":"back"},"2":{"id":""},"3":{"id":""},"4":{},"5":"Window"},"composedPath":{},"stopPropagation":{},"stopImmediatePropagation":{},"preventDefault":{},"initEvent":{}}
回答by Saurabh
So, the issue is JSON.stringify seems to bail out as soon as it finds a circular reference. I was anyway not interested in the circularly referenced properties. The way I got the rest of them is
因此,问题是 JSON.stringify 似乎在找到循环引用后立即退出。无论如何,我对循环引用的属性不感兴趣。我得到其余部分的方式是
var str = "{"
for (var key in data) {
if (JSON.stringify(data[key]) !== "") {
str += key + ":" + data[key]) + ",";
}
}
str += "}"
This will basically give you the rest of the properties. To avoid JS errors you can put if in try/catch.
这基本上将为您提供其余的属性。为避免 JS 错误,您可以将 if 放在 try/catch 中。
回答by Ali
Just use JSON.stringify(event) and event data should be converted to string.
只需使用 JSON.stringify(event) 和事件数据应转换为字符串。