Работа с API вкладок
Вкладки позволяют пользователю открыть несколько веб-страниц в окне браузера и переключаться между ними. С помощью API вкладок вы можете работать с этими вкладками и управлять ими, чтобы создавать утилиты, предоставляющие пользователям новые способы работы с вкладками или реализующие функции вашего расширения.
В этой статье пошагового руководства мы рассмотрим:
- Необходимые разрешения для использования API вкладок.
- Получение информации о вкладках и их свойствах с помощью
tabs.query. - Создание, дублирование, перемещение, обновление, перезагрузку и удаление вкладок.
- Изменение уровня масштабирования вкладки.
- Изменение CSS вкладки.
Затем мы рассмотрим другие, разнообразные функции, предоставляемые API.
Примечание: Некоторые функции API вкладок описаны в других местах. Это методы, которые можно использовать для управления содержимым вкладки с помощью скриптов (tabs.connect, tabs.sendMessage и tabs.executeScript). Если вам нужна дополнительная информация об этих методах, обратитесь к статье «Концепции» Скрипты содержимого и руководству пошагового руководства Изменение веб-страницы.
Разрешения и API вкладок
Для большинства функций API вкладок разрешения не требуются, однако есть исключения:
- Разрешение
"tabs"необходимо для доступа к свойствам объекта вкладкиTab.url,Tab.title, иTab.favIconUrl. В Firefox также необходимо разрешение"tabs"для выполнения запроса по URL. - Разрешение на хост необходимо для
tabs.executeScript()илиtabs.insertCSS().
Вот как вы можете запросить разрешение "tabs" в файле manifest.json вашего расширения:
"permissions": [ "<all_urls>", "tabs" ],
Этот запрос предоставляет вам доступ ко всем функциям API вкладок на всех посещаемых пользователем веб-сайтах. Также существует альтернативный подход для запроса разрешений на использование tabs.executeScript() или tabs.insertCSS(), где разрешение на хост не требуется, в виде "activeTab". Это разрешение предоставляет те же права, что и "tabs" с <all_urls>, но с двумя ограничениями:
- пользователь должен взаимодействовать с расширением через его браузер, значок страницы, контекстное меню или сочетание клавиш.
- разрешение действует только в активной вкладке.
Преимущество этого подхода заключается в том, что пользователь не получит предупреждение о разрешениях, указывающее, что ваше расширение может «доступ к данным для всех веб-сайтов». Это потому, что разрешение <all_urls> дает расширению возможность выполнять скрипты в любой вкладке, когда угодно, тогда как "activeTab" ограничено предоставлением расширению возможности выполнять действие, запрошенное пользователем, в текущей вкладке.
Получение информации о вкладках и их свойствах
В некоторых случаях вам потребуется список всех вкладок во всех окнах браузера. В других случаях вам может понадобиться подмножество вкладок, соответствующих определенным критериям, например, вкладок, открытых из определенной вкладки или отображающих страницы с конкретного домена. После получения списка вкладок вы, скорее всего, захотите узнать больше о их свойствах.
Для этого используется tabs.query(). Используя его самостоятельно для получения всех вкладок или с объектом queryInfo для указания критериев запроса, таких как активная вкладка, в текущем окне или по одному из 17 критериев, tabs.query() возвращает массив объектов tabs.Tab, содержащих информацию о вкладках.
Если вам нужна информация только о текущей вкладке, вы можете получить объект tabs.Tab для этой вкладки с помощью tabs.getCurrent(). Если у вас есть идентификатор вкладки, вы можете получить ее объект tabs.Tab с помощью tabs.get().
Пример пошагового руководства
Чтобы увидеть, как используются tabs.query() и tabs.Tab, давайте рассмотрим пример tabs-tabs-tabs, который добавляет список «переключения вкладок» в всплывающее окно кнопки на панели инструментов.
- manifest.json
-
Вот
manifest.json:{ "browser_action": { "browser_style": true, "default_title": "Tabs, tabs, tabs", "default_popup": "tabs.html" }, "description": "A list of methods you can perform on a tab.", "homepage_url": "https://github.com/mdn/webextensions-examples/tree/master/tabs-tabs-tabs", "manifest_version": 2, "name": "Tabs, tabs, tabs", "permissions": [ "tabs" ], "version": "1.0" }
Примечание:
-
tabs.htmlопределяется какdefault_popupвbrowser_action. Оно отображается всякий раз, когда пользователь нажимает значок расширения на панели инструментов. - Разрешения включают tabs. Это необходимо для поддержки функции списка вкладок, поскольку расширение считывает заголовок вкладок для отображения во всплывающем окне.
-
- tabs.html
-
tabs.htmlопределяет содержимое всплывающего окна расширения:<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <link rel="stylesheet" href="tabs.css" /> </head> <body> <div class="panel"> <div class="panel-section panel-section-header"> <div class="text-section-header">Tabs-tabs-tabs</div> </div> <a href="#" id="tabs-move-beginning"> Move active tab to the beginning of the window </a> <br /> <!-- Define the other menu items --> <div class="switch-tabs"> <p>Switch to tab</p> <div id="tabs-list"></div> </div> </div> <script src="tabs.js"></script> </body> </html>
Это делает следующее:
- Объявляются пункты меню.
- Объявляется пустой
divс идентификаторомtabs-listдля хранения списка вкладок. -
Вызывается
tabs.js.
- tabs.js
-
В
tabs.jsмы увидим, как создается список вкладок и добавляется во всплывающее окно.
Создание всплывающего окна
Сначала обработчик событий добавляется для выполнения listTabs() при загрузке tabs.html.
document.addEventListener("DOMContentLoaded", listTabs);
Первое, что делает listTabs() это вызов getCurrentWindowTabs(). Здесь используется tabs.query() для получения объекта tabs.Tab для вкладок в текущем окне:
function getCurrentWindowTabs() { return browser.tabs.query({ currentWindow: true }); }
Теперь listTabs() готово создать содержимое всплывающего окна.
Для начала:
- Получить элемент
<div id="tabs-list">. - Создать фрагмент документа (в который будет построен список).
- Установить счетчики.
- Очистить содержимое элемента
<div id="tabs-list">.
function listTabs() { getCurrentWindowTabs().then((tabs) => { const tabsList = document.getElementById('tabs-list'); const currentTabs = document.createDocumentFragment(); const limit = 5; let counter = 0; tabsList.textContent = '';
Далее, мы создадим ссылки для каждой вкладки:
- Проходит по первым 5 элементам объекта
tabs.Tab. - Для каждого элемента добавляется гиперссылка в фрагмент документа.
- Текст ссылки устанавливается с помощью
titleвкладки (илиid, если вкладка не имеетtitle). - Адрес ссылки устанавливается с помощью
idвкладки.
- Текст ссылки устанавливается с помощью
for (const tab of tabs) { if (!tab.active && counter <= limit) { const tabLink = document.createElement("a"); tabLink.textContent = tab.title || tab.id; tabLink.setAttribute("href", tab.id); tabLink.classList.add("switch-tabs"); currentTabs.appendChild(tabLink); } counter += 1; }
Наконец, фрагмент документа записывается в элемент <div id="tabs-list">:
tabsList.appendChild(currentTabs); }); }
Работа с активной вкладкой
Еще одна связанная функция — опция «Вывести информацию об активной вкладке», которая выводит все свойства объекта tabs.Tab для активной вкладки в диалог:
else if (e.target.id === "tabs-alertinfo") { callOnActiveTab((tab) => { let props = ""; for (const item in tab) { props += `${ item } = ${ tab[item] } \n`; } alert(props); }); }
Где callOnActiveTab() находит объект активной вкладки, перебирая объекты tabs.Tab и ища элемент с активным значением:
document.addEventListener("click", (e) => { function callOnActiveTab(callback) { getCurrentWindowTabs().then((tabs) => { for (const tab of tabs) { if (tab.active) { callback(tab, tabs); } } }); } }
Создание, дублирование, перемещение, обновление, перезагрузка и удаление вкладок
После сбора информации о вкладках, вы, скорее всего, захотите что-то с ними сделать — предоставить пользователю возможности для управления вкладками или реализовать функциональность в вашем расширении.
Доступны следующие функции:
- создание новой вкладки (
tabs.create()). - дублирование вкладки (
tabs.duplicate()). - удаление вкладки (
tabs.remove()). - перемещение вкладки (
tabs.move()). - обновление URL вкладки — переход на новую страницу — (
tabs.update()). - перезагрузка страницы вкладки (
tabs.reload()).
Примечание: Для всех этих функций требуется идентификатор (или идентификаторы) вкладки, над которой осуществляется манипулирование:
В то время как следующие функции будут действовать на активную вкладку (если не указана вкладка):
Пример использования
Пример tabs-tabs-tabs демонстрирует все эти возможности, за исключением обновления URL-адреса вкладки. Способ использования этих API похож, поэтому мы рассмотрим более сложную реализацию — опцию "Переместить активную вкладку в начало списка окон".
Но сначала вот демонстрация работы функции:
- manifest.json
-
Ни одна из функций не требует разрешений, поэтому в файле manifest.json нет никаких особенностей, требующих особого внимания.
- tabs.html
-
tabs.htmlопределяет "меню", отображаемое в всплывающем окне, которое включает опцию "Переместить активную вкладку в начало списка окон", с рядом<a>тегов, сгруппированных визуальным разделителем. Каждый пункт меню получаетid, который используется вtabs.jsдля определения, какой элемент меню запрошен.<a href="#" id="tabs-move-beginning"> Move active tab to the beginning of the window </a> <br /> <a href="#" id="tabs-move-end">Move active tab to the end of the window</a> <br /> <div class="panel-section-separator"></div> <a href="#" id="tabs-duplicate">Duplicate active tab</a><br /> <a href="#" id="tabs-reload">Reload active tab</a><br /> <a href="#" id="tabs-alertinfo">Alert active tab info</a><br />
- tabs.js
-
Для реализации "меню", определённого в
tabs.html,tabs.jsвключает обработчик кликов вtabs.html:document.addEventListener("click", (e) => { function callOnActiveTab(callback) { getCurrentWindowTabs().then((tabs) => { for (const tab of tabs) { if (tab.active) { callback(tab, tabs); } } }); } });
Затем ряд
ifоператоров пытаются сопоставитьidнажатого элемента.Этот фрагмент кода предназначен для опции "Переместить активную вкладку в начало списка окон":
if (e.target.id === "tabs-move-beginning") { callOnActiveTab((tab, tabs) => { let index = 0; if (!tab.pinned) { index = firstUnpinnedTab(tabs); } console.log(`moving ${tab.id} to ${index}`); browser.tabs.move([tab.id], { index }); }); }
Обратите внимание на использование
console.log(). Это позволяет выводить информацию в консоль отладчика отладчика, что может быть полезно при устранении проблем, возникших во время разработки.Код перемещения сначала вызывает
callOnActiveTab(), который в свою очередь вызываетgetCurrentWindowTabs(), чтобы получить объектtabs.Tab, содержащий вкладки активного окна. Затем он перебирает объект, чтобы найти и вернуть объект активной вкладки:function callOnActiveTab(callback) { getCurrentWindowTabs().then((tabs) => { for (const tab of tabs) { if (tab.active) { callback(tab, tabs); } } }); }
Закреплённые вкладки
Особенность вкладок заключается в том, что пользователь может закрепить вкладки в окне. Закреплённые вкладки помещаются в начало списка вкладок и не могут быть перемещены. Это означает, что наиболее раннее положение, куда можно переместить вкладку, — это первое положение после любых закреплённых вкладок. Следовательно, firstUnpinnedTab() вызывается для определения позиции первой незакреплённой вкладки, перебирая объект tabs:
function firstUnpinnedTab(tabs) { for (const tab of tabs) { if (!tab.pinned) { return tab.index; } } }
Теперь у нас есть всё необходимое для перемещения вкладки: объект активной вкладки, из которого можно получить вкладку id, и позицию, куда нужно переместить вкладку. Таким образом, мы можем реализовать перемещение:
browser.tabs.move([tab.id], { index });
Остальные функции для дублирования, перезагрузки, создания и удаления вкладок реализуются аналогично.
Изменение уровня масштабирования вкладки
Следующий набор функций позволяет получить (tabs.getZoom) и установить (tabs.setZoom) уровень масштабирования в вкладке. Вы также можете получить параметры масштабирования (tabs.getZoomSettings), но на момент написания утилиты возможности установки параметров (tabs.setZoomSettings) в Firefox не было.
Уровень масштабирования может быть от 30% до 500% (представлен в виде десятичных значений 0.3 до 5).
В Firefox параметры масштабирования по умолчанию:
- Уровень масштабирования по умолчанию: 100%.
- Режим масштабирования: автоматический (браузер управляет установкой уровней масштабирования).
-
Область действия изменений масштабирования:
"per-origin", что означает, что при повторном посещении сайта используется уровень масштабирования, установленный при последнем посещении.
Пример использования
Пример tabs-tabs-tabs содержит три демонстрации функции масштабирования: увеличение, уменьшение и сброс масштабирования. Вот демонстрация работы функции:
Давайте посмотрим, как реализовано увеличение масштаба.
- manifest.json
-
Ни одна из функций масштабирования не требует разрешений, поэтому в файле manifest.json нет никаких особенностей, требующих особого внимания.
- tabs.html
-
Мы уже обсуждали, как
tabs.htmlопределяет опции для этой расширения, никаких новых или уникальных действий для предоставления опций масштабирования не выполняется. - tabs.js
-
tabs.jsначинает с определения нескольких констант, используемых в коде масштабирования:const ZOOM_INCREMENT = 0.2; const MAX_ZOOM = 5; const MIN_ZOOM = 0.3; const DEFAULT_ZOOM = 1;
Затем он использует тот же обработчик кликов, о котором мы говорили ранее, чтобы реагировать на клики в
tabs.html.Для функции увеличения масштаба выполняется следующее:
else if (e.target.id === "tabs-add-zoom") { callOnActiveTab((tab) => { browser.tabs.getZoom(tab.id).then((zoomFactor) => { //the maximum zoomFactor is 5, it can't go higher if (zoomFactor >= MAX_ZOOM) { alert("Tab zoom factor is already at max!"); } else { let newZoomFactor = zoomFactor + ZOOM_INCREMENT; //if the newZoomFactor is set to higher than the max accepted //it won't change, and will never alert that it's at maximum newZoomFactor = newZoomFactor > MAX_ZOOM ? MAX_ZOOM : newZoomFactor; browser.tabs.setZoom(tab.id, newZoomFactor); } }); }); }
Этот код использует
callOnActiveTab()для получения данных активной вкладки, затемtabs.getZoomполучает текущий коэффициент масштабирования вкладки. Текущий коэффициент масштабирования сравнивается с определённым максимальным значением (MAX_ZOOM), и выводится сообщение об ошибке, если вкладка уже имеет максимальное значение масштабирования. В противном случае уровень масштабирования увеличивается, но ограничивается максимальным значением масштабирования, затем масштабирование устанавливается с помощьюtabs.getZoom.
Изменение CSS вкладки
Ещё одна важная возможность, предоставляемая API вкладок, — изменение CSS внутри вкладки: добавление нового CSS к вкладке (tabs.insertCSS()) или удаление CSS из вкладки (tabs.removeCSS()).
Это может быть полезно, например, для выделения определённых элементов страницы или изменения стандартного макета страницы.
Пример использования
Пример apply-css использует эти возможности для добавления красной рамки к веб-странице в активной вкладке. Вот пример в действии:
Давайте разберем его настройку.
- manifest.json
-
Файл
manifest.jsonзапрашивает разрешения, необходимые для использования возможностей CSS. Вам необходимо:-
"tabs"разрешение и разрешение на доступ к хосту; или, -
"activeTab"разрешение.
Второй вариант наиболее полезен, так как он позволяет расширению использовать
tabs.insertCSS()иtabs.removeCSS()в активной вкладке, когда оно запущено из действия расширения, контекстного меню или ярлыка.{ "description": "Adds a page action to toggle applying CSS to pages.", "manifest_version": 2, "name": "apply-css", "version": "1.0", "homepage_url": "https://github.com/mdn/webextensions-examples/tree/master/apply-css", "background": { "scripts": ["background.js"] }, "page_action": { "default_icon": "icons/off.svg", "browser_style": true }, "permissions": ["activeTab", "tabs"] }
Обратите внимание, что
"tabs"разрешение запрашивается дополнительно к"activeTab". Это дополнительное разрешение необходимо, чтобы скрипт расширения мог получить доступ к URL вкладки, что мы увидим в ближайшее время.Другие основные функции в файле manifest.json определяют:
- скрипт фонового процесса, который начинает выполняться сразу после загрузки расширения.
- "действие страницы", которое определяет значок, который будет добавлен в адресную строку браузера.
-
- background.js
-
При запуске
background.jsустанавливает некоторые константы для определения применяемого CSS, заголовки для "действия страницы" и список протоколов, в которых будет работать расширение:const CSS = "body { border: 20px solid red; }"; const TITLE_APPLY = "Apply CSS"; const TITLE_REMOVE = "Remove CSS"; const APPLICABLE_PROTOCOLS = ["http:", "https:"];
При первой загрузке расширение использует
tabs.query()для получения списка всех вкладок в текущем окне браузера. Затем оно перебирает вкладки, вызываяinitializePageAction().browser.tabs.query({}).then((tabs) => { for (const tab of tabs) { initializePageAction(tab); } });
initializePageActionиспользуетprotocolIsApplicable()для определения, относится ли URL активной вкладки к тем, к которым можно применить CSS:function protocolIsApplicable(url) { const anchor = document.createElement("a"); anchor.href = url; return APPLICABLE_PROTOCOLS.includes(anchor.protocol); }
Затем, если пример может воздействовать на вкладку,
initializePageAction()устанавливает значок и заголовок вкладки (панель навигации) на "выкл" перед отображениемpageAction:function initializePageAction(tab) { if (protocolIsApplicable(tab.url)) { browser.pageAction.setIcon({ tabId: tab.id, path: "icons/off.svg" }); browser.pageAction.setTitle({ tabId: tab.id, title: TITLE_APPLY }); browser.pageAction.show(tab.id); } }
Далее, обработчик события
pageAction.onClickedждет нажатия значкаpageActionи вызываетtoggleCSSпри нажатии.browser.pageAction.onClicked.addListener(toggleCSS);
toggleCSS()получает заголовокpageActionи выполняет указанные действия:-
Для "Применить CSS":
- переключает значок и заголовок на "удалить".
- применяет CSS с помощью
tabs.insertCSS().
-
Для "Удалить CSS":
- переключает значок и заголовок на "применить".
- удаляет CSS с помощью
tabs.removeCSS().
function toggleCSS(tab) { function gotTitle(title) { if (title === TITLE_APPLY) { browser.pageAction.setIcon({ tabId: tab.id, path: "icons/on.svg" }); browser.pageAction.setTitle({ tabId: tab.id, title: TITLE_REMOVE }); browser.tabs.insertCSS({ code: CSS }); } else { browser.pageAction.setIcon({ tabId: tab.id, path: "icons/off.svg" }); browser.pageAction.setTitle({ tabId: tab.id, title: TITLE_APPLY }); browser.tabs.removeCSS({ code: CSS }); } } browser.pageAction.getTitle({ tabId: tab.id }).then(gotTitle); }
Наконец, чтобы убедиться, что
pageActionдействителен после каждого обновления вкладки, обработчик событияtabs.onUpdatedвызываетinitializePageAction()каждый раз при обновлении вкладки, чтобы проверить, использует ли вкладка протокол, к которому можно применить CSS.browser.tabs.onUpdated.addListener((id, changeInfo, tab) => { initializePageAction(tab); });
-
Для "Применить CSS":
Другие интересные возможности
Есть еще несколько функций API вкладок, которые не подходят к предыдущим разделам:
- Захват видимого содержимого вкладки с помощью
tabs.captureVisibleTab. - Определение основного языка содержимого вкладки с помощью
tabs.detectLanguage. Это может быть использовано, например, для соответствия языка интерфейса расширения языку страницы, в которой он выполняется.
Дополнительная информация
Если вы хотите узнать больше о Tabs API, ознакомьтесь с:
- Справочник по Tabs API
- Примеры расширений (многие из которых используют Tabs API)
© 2005–2023 MDN contributors.
Licensed under the Creative Commons Attribution-ShareAlike License v2.5 or later.
https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Working_with_the_Tabs_API