如何对事件对象进行字符串化?
Posted
技术标签:
【中文标题】如何对事件对象进行字符串化?【英文标题】:How to stringify event object? 【发布时间】:2012-07-17 20:38:55 【问题描述】:JSON.stringify(eventObject);
给予:
TypeError: Converting circular structure to JSON
dojox.json.ref.toJson(eventObject);
给予:
TypeError: Accessing selectionEnd on an input element that cannot have a selection.
是否有一些库/代码可以用来完成它?
【问题讨论】:
您是否尝试查看结构以从对象中提取某些方法,或者您想要stringify
它的目的是什么?
调试PhoneGap - 将数据结构、事件和堆栈跟踪发送到本机层
【参考方案1】:
您将无法使用 JSON.stringify 序列化事件对象,因为事件对象包含对 DOM 节点的引用,并且 DOM 到处都有循环引用(例如,子/父关系)。默认情况下 JSON 无法处理这些,所以你有点不走运。
我建议查看How to serialize DOM node to JSON even if there are circular references?,它对如何序列化 DOM 节点有一些建议。此外,以下问题似乎提供了有用的信息:
How to save an object with circular references? Stringify (convert to JSON) a javascript object with circular reference能够处理循环引用的 JSON 库似乎是
JSON-js (see cycle.js) dojox.json.ref或者,如果你不需要它们,你可以删除所有对 DOM 节点的引用,然后序列化对象。 毕竟你不应该这样做。见@PointedEars 评论:)
【讨论】:
事件对象是host objects。 Do not mess with them,例如尝试删除其属性或分配给不应分配的属性。【参考方案2】:使用“替换器”功能避免错误:
JSON.stringify(evt, function(k, v)
if (v instanceof Node)
return 'Node';
if (v instanceof Window)
return 'Window';
return v;
, ' ');
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;
, ' ');
【讨论】:
这也只导致isTrusted: true
for MouseEvent
's
我之所以对此表示反对,只是因为有限地使用了返回“节点”的函数,而不是您通常希望从事件对象中获得的所有信息。
@PrestonBadeer 您可以创建一个自定义算法来处理循环引用、返回构造函数名称、选择器等。这取决于您。【参考方案3】:
我遇到了类似的问题,并编写了一个简单的事件序列化程序,其中包含一个帮助方法来清理事件的路径属性。此解决方案将数据从事件转换为可序列化对象的方法:
复制原始属性 为事件对象中的元素属性复制outerhtml 计算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>
【讨论】:
【参考方案4】: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);
只要这样称呼它:
stringify_object(event, 2);
例如,在一个 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":
【讨论】:
【参考方案5】:不确定它是否有帮助,但我只是在 Angular JS 文档中偶然发现了这一点:
*来源: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;
, );
现在您可以执行以下操作:
JSON.stringify(simpleKeys(eventObject));
【讨论】:
当在 touchevent 上使用它时,它只返回一个元素isTrusted: true
。
所有其他MouseEvent
's 相同【参考方案6】:
因此,问题在于 JSON.stringify 似乎在找到循环引用后立即退出。反正我对循环引用的属性不感兴趣。我得到其余的方法是
var str = ""
for (var key in data)
if (JSON.stringify(data[key]) !== "")
str += key + ":" + data[key]) + ",";
str += ""
这基本上会给你剩下的属性。为避免 JS 错误,您可以将 if 放入 try/catch。
【讨论】:
【参考方案7】:只需使用 JSON.stringify(event) 即可,事件数据应转换为字符串。
【讨论】:
以上是关于如何对事件对象进行字符串化?的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Node.js 中使用流对大型嵌套对象进行 JSON 字符串化?