通过(Runtime.ExecutionContextId)执行上下文ID(contextId)就可以获取主文档的js运行环境或框架js运行环境, 方案不只一种
async function 运行js代码及上传文件 (e) {
let { tabId: t, iframeselector: r, fileInputselector: o, jsdm: h ,files:g } = e
var n={tabId: t}
let a= await chrome.debugger.attach(n, "1.3");
let l = await chrome.debugger.sendCommand(n, "DOM.getDocument", {});
l = await chrome.debugger.sendCommand(n,"DOM.querySelector", {"nodeId": l.root.nodeId,"selector":r});
l = await chrome.debugger.sendCommand(n,"DOM.querySelector", {"nodeId": l.nodeId+1,"selector":o}); //跨框架nodeId=nodeId+1
a= await chrome.debugger.sendCommand(n, 'DOM.resolveNode',{ nodeId :l.nodeId });
a=a.object.objectId.split(".")[1]; //找到跨框架运行js代码(Runtime.evaluate)的上下文ID
await chrome.debugger.sendCommand(n, 'Runtime.evaluate', {expression: h,contextId : a }); //在框架里运行js代码
await chrome.debugger.sendCommand(n, "DOM.setFileInputFiles", {"nodeId":l.nodeId,"files":g}); //上传文件路径
}
//参数说明
tabId: 调试目标
iframeselector: iframe框架的css选择器
fileInputselector: 文件框的css选择器
jsdm: js代码
files: 需要上传文件的路径数组
//参数示例
{
tabId: 123
iframeselector:"#iframe"
fileInputselector:"#fileInput"
jsdm:"document.querySelector('#textInput').value='世界'; console.log('测试'); "
files:["C:/Users/Administrator/Desktop/11.png"]
}
原理说明:
1.通过DOM.getDocument
chrome.debugger.sendCommand({tabId: tabId}, 'DOM.getDocument',{},(result) => {console.log(result);})----->获取顶层框架(tab页)的nodeId
2.通过DOM.querySelector(第1次用)
例如iframeCSS选择器(#iframe)
chrome.debugger.sendCommand({tabId: tabId}, 'DOM.querySelector',{nodeId: nodeId,selector:"#iframe"},(result) => {console.log(result);})--->>获取到iframe的CSS选择器的nodeId,再nodeId=nodeId+1这样就获取跨框架的nodeId
3.通过DOM.querySelector(第2次用)
例如文件框CSS选择器(#fileInput) 注意这个是重点(跨框架的nodeId):nodeId=nodeId+1
chrome.debugger.sendCommand({tabId: tabId}, 'DOM.querySelector',{nodeId: nodeId,selector:"#fileInput"},(result) => {console.log(result);}) --->>获取到文件框CSS选择器的nodeId
4.通过DOM.resolveNode (DOM.resolveNod 与 DOM.requestNode 它们可以将其参数值相互转换[这个是一个关键的步骤])
chrome.debugger.sendCommand({tabId: tabId}, 'DOM.resolveNode',{ nodeId :nodeId },(result) => {console.log(result);})-------->获取到RemoteObject对象
其RemoteObject 对象中的objectId可以解析出一些东西 其中中间的这个数值(例如:5)就是需要找到的执行上下文ID的值(Runtime.ExecutionContextId),通过执行上下文ID(Runtime.ExecutionContextId)在运行js时,有重要作用,它可以直接指向框架的js运行环境,它与浏览器控制台的相通的,可以通过浏览器控制台相对应的框架中查到变量,函数等
RemoteObject 对象格式如下:
{
"className": "HTMLInputElement",
"description": "input#fileInput",
"objectId": "-6568665852511506130.5.5",这个中间值是非常有用 5 为执行上下文ID executionContextId Runtime.ExecutionContextId
"subtype": "node",
"type": "object"
}
5.Runtime.evaluate
chrome.debugger.sendCommand({ tabId: tabId }, 'Runtime.evaluate', {expression: "document.querySelector('#fileInput')",contextId : 5 (这里使用了那个中间值)}, function(response) {console.log(response);});
// js代码使用CSS选择器元素本身(如:document.querySelector('#fileInput') )------>可以返回RemoteObject——>执行上下文ID
// js代码使用CSS选择器元素属性值(如:document.querySelector('#fileInput').value )------>返回属性值的数据 这点需要注意很重要