content-script.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249
  1. function assistLoad(itemId) {
  2. // 页面为加载完毕就不断等待
  3. if (!document.body) {
  4. setTimeout(() => {
  5. assistLoad(itemId)
  6. }, 500);
  7. return
  8. }
  9. // 创建div元素
  10. const newDiv = document.createElement('div');
  11. // 设置div的内容和属性
  12. newDiv.id = 'assistBox';
  13. newDiv.className = 'assist-box';
  14. newDiv.innerHTML = `
  15. <img style="position: absolute;top: -6px;left: -13px;" onclick="window.assistBox.style.right = (window.assistBox.style.right == '-301px' ? '0' : '-301px')" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAsAAAA8CAYAAACw00AzAAABtklEQVRIie3WvU7bUBTA8b9vrKSGhKZqyAALWToQVYWhElM3pDbiG8aqcx+Al+jAAzCwdar6QVDLK3SgMDAa0g0JlGTDBmOw0bUasOHGyV2hZ7LO/d2jc+61ZPPQw5Dz2Qd/u405CbwD3piZzIDZRb0APgELnYTn+6jwEvAFyMSTGSGO7uIa8K1bTyL2/Bz4mXZHcbzRGbgXHgHm02Acv+8F43hKB4/qYEsHX+ngvuI/VuIgCMhms+Ryueg5FUvYbDZxXZdCoaDccIPzg4Mcn5ywWd+KXmrVhts2wpBnxSKNRoOv339gmib5fD6xITFgGIaUSsPYts1mvR7l5AwppxFSLpfZ+bPLr+1tBiwLwzDUWAiB4zg8HRqiMlbhwvdv1kwVNAzB8vIi1fFxWq3W/TYkdN0zzs895mZneFmtRlDOcQ9f+j5BGFCrvWVi4hXNf7DTb6KNU8ehUhnDemLRbrejI4vDRGVZRRgCz/OUMFFZLnYuQAWVR5cWjwYnvh+98IVO5WMdvKeDP+tgG/jdL5bxQQcfAh/7xTLWgdV+sYw1YBrYv5Mv9frfWAHmgNeA3w09wgCuAWMViFVtipj2AAAAAElFTkSuQmCC">
  16. `;
  17. newDiv.style.cssText = `
  18. position: fixed;
  19. right: 0;
  20. bottom: 20px;
  21. border: 1px solid #ccc;
  22. background-color: rgba(255, 255,255, 0.8);
  23. z-index: 99;
  24. transition: right 1s ease;
  25. `;
  26. // 将div插入到body的末尾
  27. document.body.appendChild(newDiv);
  28. // 创建 iframe 并插入页面
  29. const iframe = document.createElement('iframe');
  30. iframe.src = itemId ? `https://demos.run/assist/index-${itemId}.html` : 'https://demos.run/assist/index.html';
  31. iframe.style.cssText = `width: 300px;height: 400px;border: none;`
  32. setTimeout(() => {
  33. window.assistBox.appendChild(iframe);
  34. }, 0);
  35. // 向 iframe 发送消息
  36. iframe.onload = () => {
  37. iframe.contentWindow.postMessage({
  38. type: "onload",
  39. value: location.href
  40. }, '*');
  41. };
  42. function sendCallBack(callBackID, value) {
  43. if (!callBackID) return
  44. iframe.contentWindow.postMessage({
  45. type: "callBack",
  46. value,
  47. callBackID
  48. }, '*');
  49. }
  50. // 发送和接收页面
  51. const channel = new BroadcastChannel('tab_channel');
  52. // 接收消息
  53. channel.onmessage = function(event) {
  54. console.log('同源窗口消息:', event.data);
  55. if (event.data.type === 'assistTabMessage') {
  56. iframe.contentWindow.postMessage({
  57. type: "assistTabMessage",
  58. value: event.data.value,
  59. url: location.href
  60. }, '*');
  61. }
  62. };
  63. // 接收子页面发来的消息
  64. window.addEventListener('message', (event) => {
  65. // console.log('来自子页面的消息:', event.data);
  66. let domTemp = null
  67. if (event.data.target) {
  68. if (typeof event.data.target === "string") {
  69. domTemp = document.querySelector(event.data.target);
  70. } else {
  71. domTemp = document.querySelectorAll(event.data.target[0])[event.data.target[1]];
  72. }
  73. }
  74. switch (event.data.type) {
  75. // assistMsg('click','#shi')
  76. case "click":
  77. if (domTemp) {
  78. document.querySelector(event.data.target).click()
  79. sendCallBack(event.data.callBackID, {"err": 0})
  80. } else {
  81. sendCallBack(event.data.callBackID, {"err": 1, "msg": "元素不存在!"})
  82. }
  83. break;
  84. case "setValue":
  85. if (domTemp) {
  86. try {
  87. const element = domTemp;
  88. const newValue = event.data.value;
  89. // 统一处理值设置
  90. if (element.type === 'checkbox' || element.type === 'radio') {
  91. element.checked = Boolean(newValue);
  92. } else if (element.tagName === 'SELECT' && element.multiple) {
  93. // 多选select
  94. const values = Array.isArray(newValue) ? newValue : [newValue];
  95. Array.from(element.options).forEach(option => {
  96. option.selected = values.includes(option.value);
  97. });
  98. } else if (element.isContentEditable) {
  99. // 可编辑元素
  100. element.innerHTML = newValue;
  101. } else {
  102. // 普通input/textarea/select
  103. element.value = newValue;
  104. }
  105. // 触发所有可能的事件
  106. const events = [
  107. 'input', // Vue/React/Svelte
  108. 'change', // 传统框架
  109. 'blur', // 表单验证
  110. 'keyup', // 键盘事件
  111. 'keydown',
  112. 'keypress'
  113. ];
  114. events.forEach(eventType => {
  115. element.dispatchEvent(new Event(eventType, {
  116. bubbles: true,
  117. cancelable: true
  118. }));
  119. });
  120. // 额外处理特殊事件
  121. if (element.type === 'checkbox' || element.type === 'radio') {
  122. element.dispatchEvent(new Event('click', { bubbles: true }));
  123. }
  124. // 等待下一个事件循环,确保事件处理完成
  125. setTimeout(() => {
  126. // 再次触发change事件,确保异步处理完成
  127. element.dispatchEvent(new Event('change', { bubbles: true }));
  128. }, 0);
  129. sendCallBack(event.data.callBackID, {"err": 0, "msg": "设置成功"});
  130. } catch (error) {
  131. sendCallBack(event.data.callBackID, {"err": 2, "msg": `设置失败: ${error.message}`});
  132. }
  133. } else {
  134. sendCallBack(event.data.callBackID, {"err": 1, "msg": "元素不存在!"});
  135. }
  136. break;
  137. case "getInnerText":
  138. if (domTemp) {
  139. sendCallBack(event.data.callBackID, {"err": 0, "value": domTemp.innerText})
  140. } else {
  141. sendCallBack(event.data.callBackID, {"err": 1, "msg": "元素不存在!"})
  142. }
  143. break;
  144. case "getInnerHTML":
  145. if (domTemp) {
  146. sendCallBack(event.data.callBackID, {"err": 0, "value": domTemp.innerHTML})
  147. } else {
  148. sendCallBack(event.data.callBackID, {"err": 1, "msg": "元素不存在!"})
  149. }
  150. break;
  151. case "turnURL":
  152. location.href = event.data.value;
  153. break;
  154. case "getURL":
  155. sendCallBack(event.data.callBackID, {"err": 0, "value": location.href})
  156. break;
  157. // assistMsg('fetch', {
  158. // url: "https://obfuscator.lamp.run",
  159. // method: "POST",
  160. // body: "{\"code\":\"document.querySelector('.conn-box .show').innerHTML='gf'\"}",
  161. // redirect: "follow"
  162. // })
  163. case "checkElementExist":
  164. if (domTemp) {
  165. sendCallBack(event.data.callBackID, {"err": 0, "exist": true})
  166. } else {
  167. sendCallBack(event.data.callBackID, {"err": 1, "exist": false, "msg": "元素不存在!"})
  168. }
  169. case "querySelectorAll":
  170. let returnList = []
  171. let elTemp = null
  172. if (typeof event.data.value === "string") {
  173. elTemp = document.querySelectorAll(event.data.value)
  174. } else {
  175. elTemp = document.querySelectorAll(event.data.value[0])
  176. }
  177. document.querySelectorAll(event.data.value).forEach(element => {
  178. let tempObj = {
  179. id: element.id,
  180. className: element.className,
  181. }
  182. if (typeof event.data.value === "object") {
  183. event.data.value[1].forEach(key => {
  184. if (element[key]) tempObj[key] = element[key]
  185. });
  186. }
  187. returnList.push(tempObj)
  188. });
  189. sendCallBack(event.data.callBackID, returnList)
  190. break;
  191. case "fetch":
  192. chrome.runtime.sendMessage(
  193. {
  194. name: 'fetch',
  195. url: event.data.url,
  196. options: event.data.options
  197. },
  198. function(response) {
  199. console.log(response)
  200. if (response.success) {
  201. sendCallBack(event.data.callBackID, {"err": 0, "value": response.data, "headers": response.headers, "status": response.status})
  202. } else {
  203. sendCallBack(event.data.callBackID, {"err": 1, "msg": response.error})
  204. }
  205. });
  206. break;
  207. case "closeWindow":
  208. window.close();
  209. break;
  210. case "back":
  211. history.back();
  212. break;
  213. case "localStorageGetItem":
  214. sendCallBack(event.data.callBackID, localStorage.getItem(event.data.value))
  215. break;
  216. case "localStorageSetItem":
  217. localStorage.setItem(event.data.value[0], event.data.value[1])
  218. break;
  219. case "removeAttribute":
  220. document.querySelectorAll(event.data.value[0]).forEach(element => {
  221. element.removeAttribute(event.data.value[1])
  222. });
  223. break;
  224. case "sendTabMessage":
  225. // 发送消息
  226. channel.postMessage({type: 'assistTabMessage', value: event.data.value});
  227. break;
  228. default:
  229. break;
  230. }
  231. });
  232. }
  233. console.log('加载成功!')