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
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
|
---
title: 修改web页面
slug: Mozilla/Add-ons/WebExtensions/Modify_a_web_page
translation_of: Mozilla/Add-ons/WebExtensions/Modify_a_web_page
---
<div>{{AddonSidebar}}</div>
<p>浏览器附加组件( add-on )常被用于修改网页。例如更改页面的样式,隐藏特定的DOM节点或把DOM节点注入到页面中。</p>
<p>使用WebExtensions有两种方式:</p>
<ul>
<li>声明方式:定义一个网址格式,用来匹配特定的网址,然后加载脚本到对应的网页中.</li>
<li>编程方式: 使用JavaScript 接口, 将脚本加载到一个指定标签页所承载的页面中</li>
</ul>
<p>无论使用上面何种方式,它们都被称为内容脚本, 与其他脚本的区别:</p>
<ul>
<li>只能使用一部分的webextension API。</li>
<li>能读取加载了内容脚本的网页。</li>
<li>通过使用消息API与其他的webextension通信。</li>
</ul>
<p>在本文中,我们将看下加载脚本的两种方式。</p>
<h2 id="修改匹配URL的页面">修改匹配URL的页面</h2>
<p>首先,创建一个名为“ modify-page ”的文件夹,并在目录下创建“ manifest.json ”文件,内容如下:</p>
<pre class="brush: json">{
"manifest_version": 2,
"name": "modify-page",
"version": "1.0",
"content_scripts": [
{
"matches": ["https://developer.mozilla.org/*"],
"js": ["page-eater.js"]
}
]
}</pre>
<p>"content_scripts"指出符合 URL 格式的页面地址,然后让浏览器加载脚本(“ page-eater.js“)到匹配的URL页面(<a href="https://developer.mozilla.org/">https://developer.mozilla.org/</a> )。</p>
<div class="note">
<p><span id="result_box" lang="zh-CN"><span>由于</span></span> <code>content_scripts</code> <span lang="zh-CN"><span>的</span></span> <code>"js"</code> <span lang="zh-CN"><span>属性是一个数组,因此可以使用它将多个脚本注入匹配的页面。</span> <span>如果这样做,页面将按照数组中列出的顺序加载多个脚本。</span></span></p>
</div>
<div class="note">
<p><code>content_scripts</code> <span class="short_text" lang="zh-CN"><span>键还具有一个</span></span> <code>"css"</code> <span class="short_text" lang="zh-CN"><span>属性,可以使用它来注入CSS样式表。</span></span></p>
</div>
<p>在 "modify-page" 文件夹下创建“ page-eater.js ”文件,内容如下:</p>
<pre class="brush: js">document.body.textContent = "";
var header = document.createElement('h1');
header.textContent = "This page has been eaten";
document.body.appendChild(header);</pre>
<p>现在安装这个<a href="https://developer.mozilla.org/en-US/Add-ons/WebExtensions/Temporary_Installation_in_Firefox">WebExtension</a>, 然后浏览 <a href="https://developer.mozilla.org/">https://developer.mozilla.org/</a>:</p>
<p>{{EmbedYouTube("lxf2Tkg6U1M")}}</p>
<div class="note">
<p><span id="result_box" lang="zh-CN"><span>请注意,虽然此视频显示在</span></span> <a href="https://addons.mozilla.org/en-US/firefox/">addons.mozilla.org</a> <span lang="zh-CN"><span>工作的</span></span> content scripts <span lang="zh-CN"><span>,但目前该网站已禁止</span></span> content scripts <span lang="zh-CN"><span>。</span></span></p>
</div>
<h2 id="通过程序修改页面">通过程序修改页面</h2>
<p>如何修改程序使其在用户要求时才吞页面。现在修改上面的例子,在点击右键菜单项时才注入内容脚本。</p>
<p>修改 "manifest.json" 内容如下:</p>
<pre class="brush: json">{
"manifest_version": 2,
"name": "modify-page",
"version": "1.0",
"permissions": [
"activeTab",
"contextMenus"
],
"background": {
"scripts": ["background.js"]
}
}</pre>
<p>这里我们要移除"<code>content_scripts</code>"键值,并添加两个键:</p>
<ul>
<li><code><a href="/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/permissions">permissions</a></code>:要向页面中注入脚本,就需要拥有修改页面对应的权限。<a href="/en-US/Add-ons/WebExtensions/manifest.json/permissions#activeTab_permission"><code>activeTab</code></a>可以临时获得修改当前活动标签所加载的页面的权限。 另外还通过 contextmenus 来获取添加右键菜单项的权限。</li>
<li><code><a href="/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/background">background</a></code>: 加载名为 "background.js" 的 <a href="https://developer.mozilla.org/en-US/Add-ons/WebExtensions/Anatomy_of_a_WebExtension#Background_scripts">"background script"</a> (长期有效的后台脚本),在该脚本中,我们将设置注入右键菜单的内容脚本。</li>
</ul>
<p>在 "modify-page" 文件夹下创建名为 "background.js"的新文件,内容如下:</p>
<pre class="brush: js">browser.contextMenus.create({
id: "eat-page",
title: "Eat this page"
});
browser.contextMenus.onClicked.addListener(function(info, tab) {
if (info.menuItemId == "eat-page") {
browser.tabs.executeScript({
file: "page-eater.js"
});
}
});
</pre>
<p>在该脚本中我们创建了一个右键菜单项, 给了它一个具体的 id 和标题 (将在菜单中显示的文本)。 然后又设置了一个事件侦听器,当用户点击菜单项时,检查该菜单项是否就是我们的吞页菜单项。 如果是, 就通过<code><a href="/en-US/docs/Mozilla/Add-ons/WebExtensions/API/tabs/executeScript">tabs.executeScript()</a></code> 接口,把"page-eater.js" 注入到活动标签页中。 这个接口用标签ID做为参数:如果省略标签ID参数,就默认把脚本注入当前活动标签。</p>
<p>现在,附加组件看起来像这样:</p>
<pre class="line-numbers language-html"><code class="language-html">modify-page/
background.js
manifest.json
page-eater.js</code></pre>
<p>重新加载<a href="https://developer.mozilla.org/en-US/Add-ons/WebExtensions/Temporary_Installation_in_Firefox#Reloading_a_temporary_add-on">WebExtension</a>, 打开页面 (这次可以是任何一个页面) 激活右键菜单,然后选择 "Eat this page":</p>
<p>{{EmbedYouTube("zX4Bcv8VctA")}}</p>
<div class="note">
<p><span id="result_box" lang="zh-CN"><span>请注意,虽然此视频显示在</span></span> <a href="https://addons.mozilla.org/en-US/firefox/">addons.mozilla.org</a> <span lang="zh-CN"><span>工作的</span></span> content scripts <span lang="zh-CN"><span>,但目前该网站已禁止</span></span> content scripts <span lang="zh-CN"><span>。</span></span></p>
</div>
<h2 id="消息">消息</h2>
<p>内容脚本和后台脚本不能直接相互访问,但可以通过发送消息进行通信。当一端设置一个消息侦听器时,另一个端就可以发送消息了。下面的表格总结了通信时的api接口:</p>
<table class=" fullwidth-table standard-table">
<thead>
<tr>
<th scope="row"> </th>
<th scope="col">在内容脚本中</th>
<th scope="col">在后台脚本中</th>
</tr>
<tr>
<th scope="row">发送消息</th>
<td><code><a href="/en-US/Add-ons/WebExtensions/API/runtime#sendMessage()">browser.runtime.sendMessage()</a></code></td>
<td><code><a href="/en-US/Add-ons/WebExtensions/API/Tabs/sendMessage">browser.tabs.sendMessage()</a></code></td>
</tr>
<tr>
<th scope="row">接收消息</th>
<td><code><a href="/en-US/Add-ons/WebExtensions/API/runtime/onMessage">browser.runtime.onMessage</a></code></td>
<td><code><a href="/en-US/Add-ons/WebExtensions/API/runtime#onMessage">browser.runtime.onMessage</a></code></td>
</tr>
</thead>
</table>
<p>修改上面的示例,使得可以通过后台脚本来发送消息。</p>
<p>首先,修改 "background.js" 如下:</p>
<pre class="brush: js">browser.contextMenus.create({
id: "eat-page",
title: "Eat this page"
});
function messageTab(tabs) {
browser.tabs.sendMessage(tabs[0].id, {
replacement: "Message from the add-on!"
});
}
browser.contextMenus.onClicked.addListener(function(info, tab) {
if (info.menuItemId == "eat-page") {
browser.tabs.executeScript({
file: "page-eater.js"
});
var querying = browser.tabs.query({
active: true,
currentWindow: true
});
querying.then(messageTab);
}
});
</pre>
<p> 注入 "page-eater.js"后, 通过使用 <code><a href="/en-US/docs/Mozilla/Add-ons/WebExtensions/API/tabs/query">tabs.query()</a></code> 获取当前活动标签页, 然后使用<code><a href="/en-US/docs/Mozilla/Add-ons/WebExtensions/API/tabs/sendMessage">tabs.sendMessage()</a></code> 将消息发送到该标签页中的内容脚本。 该消息的内容 <code>{replacement: "Message from the add-on!"}。</code></p>
<p>接下来,修改 "page-eater.js" 如下:</p>
<pre class="brush: js">function eatPage(request, sender, sendResponse) {
document.body.textContent = "";
var header = document.createElement('h1');
header.textContent = request.replacement;
document.body.appendChild(header);
}
browser.runtime.onMessage.addListener(eatPage);
</pre>
<p>现在,不再立即执行吞页,内容脚本将先通过使用 <code><a href="https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/runtime/onMessage">runtime.onMessage</a></code>来监听消息。当监听到消息时, 内容脚本才开始运作,除了来自<code>request.replacement</code>的替换文本不一样以外,其他的脚本运作本质上与之前的相同 。</p>
<p>如果我们想将消息从内容脚本发送到后台页面,除了在内容脚本中使用 <code><a href="/en-US/docs/Mozilla/Add-ons/WebExtensions/API/runtime/sendMessage">runtime.sendMessage()</a></code> ,其他与上面的过程相反。</p>
<div class="note">
<p><span id="result_box" lang="zh-CN"><span>这些例子注入的都是JavaScript;</span> 想</span><span lang="zh-CN"><span>注入CSS可以使用</span></span> <code><a href="https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/tabs/insertCSS">tabs.insertCSS()</a></code> <span lang="zh-CN"><span>函数。</span></span></p>
</div>
<h2 id="了解更多">了解更多</h2>
<ul>
<li><a href="/en-US/docs/Mozilla/Add-ons/WebExtensions/Content_scripts">Content scripts</a> 指南</li>
<li><code><a href="/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/content_scripts">content_scripts</a></code> manifest key</li>
<li><code><a href="/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/permissions">permissions</a></code> manifest key</li>
<li><code><a href="/en-US/docs/Mozilla/Add-ons/WebExtensions/API/tabs/executeScript">tabs.executeScript()</a></code></li>
<li><code><a href="/en-US/docs/Mozilla/Add-ons/WebExtensions/API/tabs/insertCSS">tabs.insertCSS()</a></code></li>
<li><code><a href="/en-US/docs/Mozilla/Add-ons/WebExtensions/API/tabs/sendMessage">tabs.sendMessage()</a></code></li>
<li><code><a href="/en-US/docs/Mozilla/Add-ons/WebExtensions/API/runtime/sendMessage">runtime.sendMessage()</a></code></li>
<li><code><a href="/en-US/docs/Mozilla/Add-ons/WebExtensions/API/runtime/onMessage">runtime.onMessage</a></code></li>
<li>使用<code>content_scripts</code>的例子:
<ul>
<li><a href="https://github.com/mdn/webextensions-examples/tree/master/borderify">borderify</a></li>
<li><a href="https://github.com/mdn/webextensions-examples/tree/master/inpage-toolbar-ui">inpage-toolbar-ui</a></li>
<li><a href="https://github.com/mdn/webextensions-examples/tree/master/notify-link-clicks-i18n">notify-link-clicks-i18n</a></li>
<li><a href="https://github.com/mdn/webextensions-examples/tree/master/page-to-extension-messaging">page-to-extension-messaging</a></li>
</ul>
</li>
<li>使用<code>tabs.executeScript()</code>的例子:
<ul>
<li><a class="external external-icon" href="https://github.com/mdn/webextensions-examples/tree/master/beastify">beastify</a></li>
<li><a class="external external-icon" href="https://github.com/mdn/webextensions-examples/tree/master/context-menu-demo">context-menu-demo</a></li>
</ul>
</li>
</ul>
<p> </p>
|