Chrome DevTools扩展:如何从内容脚本中的元素面板获取选定的元素? [英] Chrome DevTools extension: how to get selected element from elements panel in content script?

查看:551
本文介绍了Chrome DevTools扩展:如何从内容脚本中的元素面板获取选定的元素?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经完成了我的研究,并且一直在努力,但我需要您的帮助。



我正在构建Chrome DevTools扩展。它应该将当前选中的元素从面板作为参考传递给内容脚本中定义的JS对象。



它我将引用传递给所选元素,或者从内容脚本中标识元素的其他方式是非常重要的。



我理解Chrome DevTools中的孤立的世界工作流程。我也了解扩展页面,后台页面和内容脚本之间的消息。这只会发生在JSON基元中,因此不会传递JS范围。



如何将devtools Elements面板中选定的元素传递给检查页面中的内容脚本?



编辑



这是我迄今所知道的: b
$ b

获取对所选元素的引用:

  chrome.devtools.inspectedWindow.eval (+ function(){console.log($ 0)} .toString()+)())




  • 该函数表达式将在被检查页面的上下文中运行,而不是在devtools扩展的上下文中运行,而不是在内容的孤立世界上下文中运行脚本。我不相信有可能使用闭包来传递对不同上下文的引用。 所选DOM元素 $ 0 的引用无法返回,因为它不能由于循环引用而序列化为JSON。

  • devtools扩展页面。 $ 0 引用不能在 chrome.devtools.inspectedWindow




解决方法



使用共享的DOM标记所选元素的数据属性,并使用它在内容脚本的上下文中重新选择它。消息传递用于传递数据属性标记。



以下是代码的简化版本:



devtools扩展页:

  //设置通讯端口
port = chrome。 runtime.connect({name:devtools});

chrome.devtools.panels.elements.onSelectionChanged.addListener(function(){

//在检查页面的上下文中运行表达式
var expression =(+ mark.toString()+)()

//计算表达式并处理结果
chrome.devtools.inspectedWindow.eval(expression,dispatchToContentScript)
});


函数mark(){

//标记当前选定的元素
$ 0.setAttribute('data-selected')

//将标记发送到回调函数
return {marker:'data-selected'}
}

函数dispatchToContentScript(data){

//将数据发送到正在侦听同一端口的内容脚本。
port.postMessage(data)
}

内容脚本

  var port = chrome.runtime.connect({name:devtools}); 

port.onMessage.addListener(function(data){

//在内容脚本的上下文中重新选择元素
var el = document。 querySelector('['+ data.marker +']')
})

不是一个干净的解决方案,但我可以用它来满足我的需求。

是否有更简单的方法来实现相同的结果 - 从内容脚本中识别在devtools的元素面板中选择的元素?


chrome.devtools.inspectedWindow 已更新,以支持在内容脚本的上下文中执行脚本。



官方Chrome API中的这一更新过时了我们上述的黑客行为。我们现在可以通过以下方式实现预期结果:

  chrome.devtools.inspectedWindow.eval(aContentScriptFunction($ 0),
{useContentScriptContext:true});

$ 0 参数将引用所选元素在元素面板中。


I've done my research and struggled with this for a while, but I need your help.

I'm building a Chrome DevTools extension. It should should pass the currently selected element from the 'Elements' panel as a reference to a JS object defined in a content script.

It is important that I pass the reference to the selected element, or some other way of identifying the element from the content script.

I understand the workflow with 'isolated worlds' in Chrome DevTools. I also understand messaging between extension pages, background page and content scripts. This only happens with JSON primitives, hence no JS scope passing.

How can I pass the element selected in devtools Elements panel to the content script that lives in the inspected page?

Edit

Here's what I know so far:

Getting a reference to the selected element:

chrome.devtools.inspectedWindow.eval("(" + function(){ console.log($0) }.toString() + ")()")

  • That function expression will run in the context of the inspected page, not in the context of the devtools extension and not in the context of the 'isolated world' of the content script. I don't believe it is possible to pass in a reference to a different context using closures.

  • The reference to the selected DOM element $0 can't be returned because it can't be serialized to JSON due to circular references.

  • The chrome.devtools namespace isn't available outside the devtools extension page. The $0 reference can't be used outside the evaluated expression in chrome.devtools.inspectedWindow

Workaround

As a workaround, I chose to use the shared DOM to mark the selected element with a data attribute and use that to re-select it in the context of the content script. Messaging is used to pass the data attribute marker around.

Here's a simplified version of the code:

In the devtools extension page:

// setup a communication port
port = chrome.runtime.connect({name: "devtools"});

chrome.devtools.panels.elements.onSelectionChanged.addListener(function(){

  // expression to run in the context of the inspected page
  var expression = "(" + mark.toString() + ")()"

  // evaluate the expression and handle the result
  chrome.devtools.inspectedWindow.eval(expression, dispatchToContentScript)
});


function mark(){

  // mark the currently selected element
  $0.setAttribute('data-selected')

  // send the marker to the callback
  return { marker: 'data-selected' }
}

function dispatchToContentScript(data){

  // dispatch data to the content script which is listening to the same port.
  port.postMessage(data)
}

In the content script:

var port = chrome.runtime.connect({name: "devtools"});

port.onMessage.addListener(function(data) {

  // re-select the element in the context of the content script
  var el = document.querySelector('['+ data.marker +']')
})

It's not a clean solution but I can use it for my needs.

Is there a simpler way to achieve the same result - identify from a content script the element selected in the devtools 'Elements' panel?

解决方案

The API for chrome.devtools.inspectedWindow has been updated to support executing scripts in the context of the content script.

This update in the official Chrome API obsoletes our hacks described above. We can now achieve the expected result with:

chrome.devtools.inspectedWindow.eval("aContentScriptFunction($0)", 
    { useContentScriptContext: true });

The $0 parameter will reference the element selected in the Elements panel.

这篇关于Chrome DevTools扩展:如何从内容脚本中的元素面板获取选定的元素?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆