【油猴脚本 Greasemonkey】GM_xmlhttpRequest内部实现原理
微wx笑
2022-11-01【前端开发】
191
2
0关键字:
油猴脚本 Greasemonkey
多数扩展脚本都会用到网络请求功能,对应的【油猴脚本 Greasemonkey】就是调用 GM_xmlhttpRequest 函数,这个函数内部是怎么实现的呢?拿到一段油猴脚本想用在自己开发的Chrome扩展中,但是用到了 GM_xmlhttpRequest 函数怎么办?
本文来讲一下实现原理,附代码。
目录
多数扩展脚本都会用到网络请求功能,对应的【油猴脚本 Greasemonkey】就是调用 GM_xmlhttpRequest 函数,这个函数内部是怎么实现的呢?拿到一段油猴脚本想用在自己开发的Chrome扩展中,但是用到了 GM_xmlhttpRequest 函数怎么办?
本文来讲一下实现原理,附代码。
缘起
网页上的即时翻译功能,大家用的较多的就是 划词翻译 了吧,但是今年以来互联网开始由开放转为封闭,很多原来免费的功能现在转为收费了,很多免费使用的翻译接口,现在虽然还没有完全收费,但是也需要自己去申请之后才能使用,这就是在收集用户信息了,只是第一步,接下来估计收费是一个趋势。
相关事件:搜狗翻译的官方平台搜狗深智引擎开放平台发出公告,将于 2022 年 2 月 28 日停止服务,公告具体内容可前往搜狗深智引擎开放平台官网查看。
百度翻译2022年7月14日发送了邮件通知,将从 8 月 1 日起下调每月的免费额度。
调整前免费额度 | 调整后免费额度 | |
---|---|---|
标准版 | 无限量 | 5 万字符 / 月 |
高级版 | 200 万字符 / 月 | 100 万字符 / 月 |
刚好自己最近也在研究Chrome扩展的开发,基本算了入门了一点点,所以就考虑自己实现一个划词翻译的功能。
于是网上找划词翻译的源码参考,就找到了 有道划词翻译 的一段源码分享,是基于油猴脚本的,
有道划词翻译源码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 | // ==UserScript== // @name 有道划词翻译 // @version 0.111 // @author Jim Lin // @originalAuthor Liu Yuyang(sa@linuxer.me) // @match http://*/* // @description 极简 // @grant GM_xmlhttpRequest // @namespace https://greasyfork.org/users/25855 // ==/UserScript== window.document.body.addEventListener('mouseup', translate, false); var context = new AudioContext(); function translate(e) { var previous = document.querySelector('.youdaoPopup'); if (previous) { document.body.removeChild(previous); } var selectObj = document.getSelection(); if (selectObj.anchorNode.nodeType == 3) { var word = selectObj.toString(); if (word == '') { return; } word = word.replace('-\n', ''); word = word.replace('\n', ' '); var ts = new Date().getTime(); var x = e.clientX; var y = e.clientY; translate(word, ts); } function popup(x, y, result) { var youdaoWindow = document.createElement('div'); youdaoWindow.classList.toggle('youdaoPopup'); var dict = JSON.parse(result); var query = dict['query']; var errorCode = dict['errorCode']; if (dict['basic']) { word(); } else { sentence(); } youdaoWindow.style.zIndex = '1024'; youdaoWindow.style.display = 'block'; youdaoWindow.style.position = 'fixed'; youdaoWindow.style.color = 'black'; youdaoWindow.style.textAlign = 'left'; youdaoWindow.style.wordWrap = 'break-word'; youdaoWindow.style.background = 'lightBlue'; youdaoWindow.style.borderRadius = '5px'; youdaoWindow.style.boxShadow = '0 0 5px 0'; youdaoWindow.style.opacity = '1'; youdaoWindow.style.width = '200px'; youdaoWindow.style.left = x + 10 + 'px'; youdaoWindow.style.padding = '5px'; if (x + 200 + 10 >= window.innerWidth) { youdaoWindow.style.left = parseInt(youdaoWindow.style.left) - 200 + 'px'; } if (y + youdaoWindow.offsetHeight + 10 >= window.innerHeight) { youdaoWindow.style.bottom = '20px'; } else { youdaoWindow.style.top = y + 10 + 'px'; } document.body.appendChild(youdaoWindow); function word() { var basic = dict['basic']; var header = document.createElement('p'); var span = document.createElement('span'); span.innerHTML = query; header.appendChild(span); var phonetic = basic['phonetic']; if (phonetic) { var phoneticNode = document.createElement('span'); phoneticNode.innerHTML = '[' + phonetic + ']'; phoneticNode.style.cursor = 'pointer'; header.appendChild(phoneticNode); phoneticNode.addEventListener('mouseup', function (e) { e.stopPropagation() }, false); var soundUrl = 'https://dict.youdao.com/dictvoice?type=2&audio={}'.replace('{}', query); var promise = new Promise(function () { GM_xmlhttpRequest({ method: 'GET', url: soundUrl, responseType: 'arraybuffer', onload: function (res) { try { context.decodeAudioData(res.response, function (buffer) { phoneticNode.addEventListener('mouseup', function () { var source = context.createBufferSource(); source.buffer = buffer; source.connect(context.destination); source.start(0); }, false); header.appendChild(document.createTextNode('✓')); }) } catch (e) { } } }); }); promise.then(); } header.style.color = 'darkBlue'; header.style.margin = '0'; header.style.padding = '0'; span.style.color = 'black'; youdaoWindow.appendChild(header); var hr = document.createElement('hr'); hr.style.margin = '0'; hr.style.padding = '0'; youdaoWindow.appendChild(hr); var ul = document.createElement('ul'); ul.style.margin = '0'; ul.style.padding = '0'; basic['explains'].map(function (trans) { var li = document.createElement('li'); li.style.listStyle = 'none'; li.style.margin = '0'; li.style.padding = '0'; li.appendChild(document.createTextNode(trans)); ul.appendChild(li); }); youdaoWindow.appendChild(ul); } function sentence() { var ul = document.createElement('ul'); ul.style.margin = '0'; ul.style.padding = '0'; dict['translation'].map(function (trans) { var li = document.createElement('li'); li.style.listStyle = 'none'; li.style.margin = '0'; li.style.padding = '0'; li.appendChild(document.createTextNode(trans)); ul.appendChild(li); }); youdaoWindow.appendChild(ul); } } function translate(word, ts) { var reqUrl = 'http://fanyi.youdao.com/openapi.do?type=data&doctype=json&version=1.1&relatedUrl=' + escape('http://fanyi.youdao.com/#') + '&keyfrom=fanyiweb&key=null&translate=on' + '&q={}'.replace('{}', word) + '&ts={}'.replace('{}', ts); GM_xmlhttpRequest({ method: 'GET', url: reqUrl, onload: function (res) { popup(x, y, res.response); } }); } } |
实现原理
上面代码中就用到了 GM_xmlhttpRequest 函数,自己如何实现这个函数呢?
用过 ajax,xmlhttpRequest 的小伙伴看到这个函数的调用方法应该感觉非常熟悉,和 ajax 的调用基本差不多,无非是把调用成功的响应事件由 success 改成了 onload
所以自己定义一个函数,内部封装 ajax 的调用就可以了。
但是需要注意,你的扩展程序运行在别人的网站上,发出的请求基本都是跨域的请求,仅仅封装 ajax 是不行的,这就需要根据Chrome扩展提供的能力、方法来实现跨域请求;
具体实现代码参考:
【Chrome扩展程序】利用 background 实现跨域请求
本文由 微wx笑 创作,采用 署名-非商业性使用-相同方式共享 4.0 许可协议,转载请附上原文出处链接及本声明。
原文链接:https://www.ivu4e.cn/blog/front/2022-11-01/1564.html