前端开发您现在的位置是:首页 > 博客日志 > 前端开发

【油猴脚本 Greasemonkey】GM_xmlhttpRequest内部实现原理

<a href='mailto:'>微wx笑</a>的头像微wx笑 2022-11-01前端开发191 2 0关键字: 油猴脚本  Greasemonkey  

多数扩展脚本都会用到网络请求功能,对应的【油猴脚本 Greasemonkey】就是调用 GM_xmlhttpRequest 函数,这个函数内部是怎么实现的呢?拿到一段油猴脚本想用在自己开发的Chrome扩展中,但是用到了 GM_xmlhttpRequest 函数怎么办?
本文来讲一下实现原理,附代码。

多数扩展脚本都会用到网络请求功能,对应的【油猴脚本 Greasemonkey】就是调用 GM_xmlhttpRequest 函数,这个函数内部是怎么实现的呢?拿到一段油猴脚本想用在自己开发的Chrome扩展中,但是用到了 GM_xmlhttpRequest 函数怎么办?UlI无知

本文来讲一下实现原理,附代码。UlI无知


UlI无知

缘起

网页上的即时翻译功能,大家用的较多的就是 划词翻译 了吧,但是今年以来互联网开始由开放转为封闭,很多原来免费的功能现在转为收费了,很多免费使用的翻译接口,现在虽然还没有完全收费,但是也需要自己去申请之后才能使用,这就是在收集用户信息了,只是第一步,接下来估计收费是一个趋势。UlI无知

相关事件:搜狗翻译的官方平台搜狗深智引擎开放平台发出公告,将于 2022 年 2 月 28 日停止服务,公告具体内容可前往搜狗深智引擎开放平台官网查看。UlI无知

百度翻译2022年7月14日发送了邮件通知,将从 8 月 1 日起下调每月的免费额度。UlI无知

调整前免费额度调整后免费额度
标准版无限量5 万字符 / 月
高级版200 万字符 / 月100 万字符 / 月
刚刚看到新闻:腾讯开始对会议收费UlI无知


UlI无知

刚好自己最近也在研究Chrome扩展的开发,基本算了入门了一点点,所以就考虑自己实现一个划词翻译的功能。UlI无知

于是网上找划词翻译的源码参考,就找到了 有道划词翻译 的一段源码分享,是基于油猴脚本的,UlI无知

有道划词翻译源码

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 函数,自己如何实现这个函数呢?UlI无知

用过 ajax,xmlhttpRequest 的小伙伴看到这个函数的调用方法应该感觉非常熟悉,和 ajax 的调用基本差不多,无非是把调用成功的响应事件由 success 改成了 onloadUlI无知

所以自己定义一个函数,内部封装 ajax 的调用就可以了。UlI无知

但是需要注意,你的扩展程序运行在别人的网站上,发出的请求基本都是跨域的请求,仅仅封装 ajax 是不行的,这就需要根据Chrome扩展提供的能力、方法来实现跨域请求;UlI无知

具体实现代码参考:UlI无知

【Chrome扩展程序】利用 background 实现跨域请求UlI无知


UlI无知

本文由 微wx笑 创作,采用 署名-非商业性使用-相同方式共享 4.0 许可协议,转载请附上原文出处链接及本声明。
原文链接:https://www.ivu4e.cn/blog/front/2022-11-01/1564.html

很赞哦! (22) 有话说 (0)

相关文章

文章评论