【问题标题】:Send DOM node object via chrome.tabs.sendMessage通过 chrome.tabs.sendMessage 发送 DOM 节点对象
【发布时间】:2021-04-21 17:29:24
【问题描述】:

我正在编写一个 Chrome 扩展程序。我需要将元素对象从内容脚本传递到后台脚本。

目标:
该扩展是关于记录和回放用户操作的。
数据保存在每个选项卡的不同对象上的扩展本地存储中(按选项卡 ID)。
数据结构是{x: x, y:y, element: element}的列表
当用户想要重播时,我对列表中的每个对象使用循环并在元素上使用.click()

内容脚本中的代码:

向后台脚本发送消息的函数:

function addToEventHistory(cords) {
    console.log(cords)
    chrome.runtime.sendMessage({action: "addToEventHistory", cords: cords}, function(response) {
        return response;
    });
}

获取元素并感知它的函数:

mouseClick: function(e) {
                var target = e.target || e.srcElement
                var clickEvent = {x: e.pageX, y: e.pageY, element: target}
                addToEventHistory(clickEvent)
            }

后台脚本中的代码:

var tabId = sender.tab.id;
var existingRecords = JSON.parse(localStorage.getItem('record_'+tabId)) || [];
existingRecords.push(request.cords)
console.log(request.cords)
localStorage.setItem('record_'+tabId, JSON.stringify(existingRecords));
sendResponse();

问题是我发送的元素被接收为一个空对象。在发送和接收时通知console.log。输出是:

发送:

Object {x: 1205, y: 1067, element: div#content.snippet-hidden}

接收:

Object {x: 1205, y: 1067, element: Object}

* 元素对象为空,只有_proto_

是什么原因?
我该如何解决这个问题?

看起来问题不在于序列化 DOM 对象,因为该对象在发送之前看起来还可以,而在接收时则不行。..

【问题讨论】:

  • 看起来问题不在于序列化 DOM 对象,因为该对象在发送之前看起来还可以,而在接收时却不行。..
  • tabs.sendMessage 中的消息必须是“JSON-ifiable object”。 DOM 元素不是 JSON 格式的。因此,您不能发送它们。如果要识别元素,则需要确定(或定义;例如分配 ID)唯一选择器。最终,您需要做什么而不是尝试序列化 DOM 元素取决于您在后台脚本中需要此信息的原因。
  • 我需要在扩展的本地存储中保存 DOM 对象。 DOM 对象有时可能没有 ID,因此需要保存整个元素。
  • 你不能做你想做的事。因此,您将需要找到其他方法来实现您的实际目标。您尚未说明您的实际目标,因此我们无法就您如何实现该目标提出建议。我们已经达到了XY problem 的位置。

标签: javascript google-chrome google-chrome-extension


【解决方案1】:

您不能将 DOM 元素作为 runtime.sendMessage() 消息发送

runtime.sendMessage() 中的消息必须是“JSON-ifiable object”。 DOM 元素/节点不是 JSON 格式的。因此,您不能发送它们。在您的情况下,您正在尝试发送 click 事件的 target

最终,您需要做什么而不是尝试序列化 DOM 元素取决于您在后台脚本中需要此信息的原因。

如果你想识别元素,你需要确定一个唯一的选择器。一种方法是为元素分配一个唯一的 ID 并在您的消息中传递该 ID。但是,只有当您希望在该选项卡中加载页面时引用 DOM 节点时,这才会有效。显然,一旦浏览器离开页面或将其加载到不同的选项卡中,您分配的任何 ID 都将不可用。因此,该替代方案仅适用于在当前页面的生命周期内识别元素。但是,对于您只想存储实际 DOM 元素的应用程序,分配唯一 ID 将是一个有效的解决方案。换句话说,存储 DOM 元素只会在页面的生命周期内有效,因此分配唯一 ID 将在相同的时间段(当前页面的生命周期)内有效。

如果您想要在重新加载页面时唯一标识元素的方法,则需要使用与分配 ID 不同的方法。使用什么在很大程度上取决于您在想要使用元素时如何选择元素,以及您希望选择对页面结构的变化有多大的弹性(例如,在结构是动态的页面上,您可能需要使用其他方法,而不是在静态页面上工作)。

对于您想要记录和回放用户操作的应用程序,您需要根据鼠标在页面中的位置或用户发起事件的元素来确定是否要记录这些操作.这是用于记录/播放/模拟用户操作的应用程序/语言的常见问题。通常,用户可以选择他们希望如何记录这种用户交互(例如,通过位置或元素)。如果您选择仅通过事件发生时鼠标的位置来存储用户操作,那么您可以使用Document.elementFromPoint() 来确定此时 now 的元素并将事件发送到那个元素。但是,这样做时,您还需要跟踪文档的滚动状态,并确定是否要根据鼠标在当前显示中的位置或相对于文档的位置来存储鼠标的位置。

【讨论】:

    【解决方案2】:

    我使用了一种解决方法来单击该元素,

    除了保存元素然后使用element.click()之外,我还使用绳索单击元素而不保存元素本身:

    document.elementFromPoint(cords.x - window.pageXOffset, cords.y - window.pageYOffset).click();
    

    【讨论】:

      猜你喜欢
      • 2014-08-05
      • 2012-08-29
      • 1970-01-01
      • 2012-06-19
      • 2015-10-04
      • 1970-01-01
      • 1970-01-01
      • 2017-02-04
      相关资源
      最近更新 更多