• AFFHUB CONNECT WARSAW MEETUP: покупайте билеты по ссылке
  • AFFHUB CONNECT WARSAW MEETUP: покупайте билеты по ссылке
  • AFFHUB CONNECT WARSAW MEETUP: покупайте билеты по ссылке
img
img
  • 2
  • 0
  • 0

Как создать собственное расширение для Хром, которое убирает мусор с сайта

Думаем, почти у каждого возникала пассивная борьба с мусором на веб-сайте, в которой пользователь так и не одерживал желаемой победы.

Как вы понимаете, речь идет о многочисленных рекламных объявлениях на сайтах, которые часто мешают просматривать материал, всплывающие окна и т. п. Кому-то это безразлично, а для кого-то — настоящий кошмар. 

Что ж, спасибо технологиям, которые позволяют решить эту проблему и устранить неудобства при просмотре сайтов. В статье мы разберем, как создать расширение, которое убирает мусор и позволяет комфортно пользоваться браузером.

Подробности ищите ниже. Поехали разбираться!

Немного о структуре расширения

Наше расширение будет состоять из:

  • manifest.json — файл, который даст понять браузеру, что это именно расширение.  
  • content.js — файл, в котором будет сосредоточена основная логика работы расширения.
  • background.js — логика работы контекстного меню. 
  • popup.html — меню управления включением и выключением расширения на веб-сайтах.
  • popup.js — логика предыдущего меню.

Как создать это расширение?

Сначала нужно создать папку с любым именем, а уже в ней создаем 5 вышеупомянутых файлов (manifest.json, content.js, background.js, popup.html, popup.js). 

Далее следуем следующему алгоритму действий:

  1. Открываем manifest.json и вставляем в него:

{

“manifest_version”:3,

“name”:”Element Cleaner Per Site”,

“version”:”2.0.0″,

“description”:”Удаление элементов страниц через контекстное меню с включением по отдельным сайтам.”,

“permissions”:[

“contextMenus”,

“tabs”,

“storage”,

“activeTab”

],

“host_permissions”:[

“<all_urls>”

],

“background”:{

“service_worker”:”background.js”

},

“action”:{

“default_title”:”Element Cleaner”,

“default_popup”:”popup.html”

},

“content_scripts”:[

{

“matches”:[

“<all_urls>”

],

“js”:[

“content.js”

],

“run_at”:”document_start”

}

]

}

  1. Сохраняем manifest.json
  2. Открываем content.js и вставляем в него:

let selectedElement=null;

let hoverElement=null;

let extensionEnabled=false;

let lastOutline=””;

function checkState(){

chrome.storage.sync.get(

[“enabledSites”],

result=>{

const sites=

Array.isArray(result.enabledSites)

? result.enabledSites

: [];

extensionEnabled=

sites.includes(location.hostname);

if(!extensionEnabled){

removeHighlight();

}

}

);

}

function applyHighlight(element){

if(!element) return;

if(hoverElement===element){

return;

}

removeHighlight();

hoverElement=element;

lastOutline=

element.style.outline;

element.style.outline=

“3px solid red”;

element.style.outlineOffset=

“2px”;

}

function removeHighlight(){

if(hoverElement){

hoverElement.style.outline=

lastOutline || “”;

hoverElement.style.outlineOffset=””;

}

hoverElement=null;

lastOutline=””;

}

document.addEventListener(

“mousemove”,

event=>{

if(!extensionEnabled){

return;

}

const element=

event.target;

if(

element &&

element!==document.body &&

element!==document.documentElement

){

applyHighlight(element);

}

},

true

);

document.addEventListener(

“mouseleave”,

()=>{

removeHighlight();

},

true

);

document.addEventListener(

“contextmenu”,

event=>{

if(!extensionEnabled){

return;

}

selectedElement=

event.target;

applyHighlight(selectedElement);

},

true

);

chrome.storage.onChanged.addListener(()=>{

checkState();

});

chrome.runtime.onMessage.addListener(

message=>{

if(message.action===”remove_element”){

if(

extensionEnabled &&

selectedElement

){

selectedElement.remove();

selectedElement=null;

}

}

if(message.action===”remove_parent_element”){

if(

extensionEnabled &&

selectedElement

){

const parent=

selectedElement.parentElement;

if(parent){

parent.remove();

}

selectedElement=null;

}

}

}

);

checkState();

  1. Сохраняем content.js
  2. Открываем background.js и вставляем:

const REMOVE_MENU_ID=”remove_element”;

const REMOVE_PARENT_MENU_ID=”remove_parent_element”;

function getHostname(url){

try{

return new URL(url).hostname;

}catch(e){

return “”;

}

}

function getEnabledSites(){

return new Promise(resolve=>{

chrome.storage.sync.get(

[“enabledSites”],

result=>{

resolve(

Array.isArray(result.enabledSites)

? result.enabledSites

: []

);

}

);

});

}

async function isEnabledForTab(tab){

if(!tab || !tab.url){

return false;

}

const hostname=getHostname(tab.url);

const sites=await getEnabledSites();

return sites.includes(hostname);

}

function createContextMenu(){

chrome.contextMenus.removeAll(()=>{

chrome.contextMenus.create({

id:REMOVE_MENU_ID,

title:”Удалить элемент”,

contexts:[“all”]

});

chrome.contextMenus.create({

id:REMOVE_PARENT_MENU_ID,

title:”Удалить родительский элемент”,

contexts:[“all”]

});

});

}

async function refreshMenu(tabId,url){

const enabled=

(await getEnabledSites())

.includes(getHostname(url));

if(enabled){

createContextMenu();

}else{

chrome.contextMenus.removeAll();

}

}

chrome.runtime.onInstalled.addListener(()=>{

chrome.contextMenus.removeAll();

});

chrome.storage.onChanged.addListener(()=>{

chrome.tabs.query(

{},

tabs=>{

tabs.forEach(tab=>{

if(tab.url){

refreshMenu(

tab.id,

tab.url

);

}

});

}

);

});

chrome.tabs.onActivated.addListener(info=>{

chrome.tabs.get(

info.tabId,

tab=>{

if(tab && tab.url){

refreshMenu(

tab.id,

tab.url

);

}

}

);

});

chrome.tabs.onUpdated.addListener(

(tabId,changeInfo,tab)=>{

if(changeInfo.url){

refreshMenu(

tabId,

changeInfo.url

);

}

}

);

chrome.contextMenus.onClicked.addListener(

async(info,tab)=>{

if(!await isEnabledForTab(tab)){

return;

}

chrome.tabs.sendMessage(

tab.id,

{

action:info.menuItemId

}

);

}

);

  1. Сохраняем background.js
  2. Открываем popup.html и вставляем:

<!DOCTYPE html>

<html lang=”ru”>

<head>

<meta charset=”UTF-8″>

<title>Element Cleaner</title>

<style>

body{

width:350px;

padding:14px;

margin:0;

font-family:Arial,sans-serif;

background:#f7f7f7;

color:#222;

}

h2{

margin:0 0 12px 0;

font-size:20px;

}

.description{

font-size:12px;

opacity:.75;

line-height:1.4;

margin-bottom:12px;

}

.panel{

background:white;

border:1px solid #d5d5d5;

padding:10px;

margin-bottom:12px;

}

.caption{

font-size:12px;

opacity:.7;

}

.current-site{

margin-top:6px;

font-weight:bold;

word-break:break-all;

}

.status{

margin-top:8px;

padding:6px;

text-align:center;

border:1px solid #ddd;

font-size:12px;

}

button{

width:100%;

padding:8px;

margin-top:8px;

cursor:pointer;

}

.sites-title{

margin-bottom:8px;

}

.sites-list{

max-height:170px;

overflow-y:auto;

border:1px solid #ddd;

background:#fff;

}

.site-row{

display:flex;

justify-content:space-between;

align-items:center;

padding:6px;

border-bottom:1px solid #eee;

font-size:12px;

}

.site-name{

overflow:hidden;

text-overflow:ellipsis;

}

.delete-button{

width:auto;

margin:0;

padding:3px 8px;

}

.empty{

padding:8px;

opacity:.6;

font-size:12px;

}

.footer{

margin-top:10px;

text-align:center;

font-size:11px;

opacity:.5;

}

</style>

</head>

<body>

<h2>

Element Cleaner

</h2>

<div class=”description”>

Расширение полностью включается только на выбранных сайтах.

На остальных страницах оно не добавляет пункты в контекстное меню.

</div>

<div class=”panel”>

<div class=”caption”>

Текущий сайт:

</div>

<div

id=”currentSite”

class=”current-site”

>

Определение…

</div>

<div

id=”status”

class=”status”

>

Проверка состояния…

</div>

<button

id=”toggleButton”

>

Загрузка…

</button>

</div>

<div class=”panel”>

<div class=”sites-title”>

Активные сайты:

</div>

<div

id=”sitesList”

class=”sites-list”

>

</div>

<button

id=”addButton”

>

Добавить текущий сайт

</button>

</div>

<div class=”footer”>

Element Cleaner • Site control

</div>

<script src=”popup.js”></script>

</body>

</html>

  1. Сохраняем popup.html
  2. Открываем popup.js и вставляем:

const currentSiteElement =

document.getElementById(“currentSite”);

const statusElement =

document.getElementById(“status”);

const toggleButton =

document.getElementById(“toggleButton”);

const addButton =

document.getElementById(“addButton”);

const sitesListElement =

document.getElementById(“sitesList”);

let currentHostname=””;

let enabledSites=[];

function getCurrentTab(){

return new Promise(resolve=>{

chrome.tabs.query(

{

active:true,

currentWindow:true

},

tabs=>{

if(tabs && tabs[0]){

resolve(tabs[0]);

}else{

resolve(null);

}

}

);

});

}

function extractHostname(url){

try{

return new URL(url).hostname;

}catch(error){

return “”;

}

}

function loadEnabledSites(){

return new Promise(resolve=>{

chrome.storage.sync.get(

[“enabledSites”],

result=>{

if(

result &&

Array.isArray(result.enabledSites)

){

resolve(

result.enabledSites

);

}else{

resolve([]);

}

}

);

});

}

function saveEnabledSites(list){

return new Promise(resolve=>{

chrome.storage.sync.set(

{

enabledSites:list

},

()=>{

resolve();

}

);

});

}

function isEnabled(site){

return enabledSites.includes(site);

}

function updateStatus(){

if(isEnabled(currentHostname)){

statusElement.textContent=

“Расширение активно на этом сайте”;

toggleButton.textContent=

“Выключить расширение на сайте”;

}else{

statusElement.textContent=

“Расширение выключено на этом сайте”;

toggleButton.textContent=

“Включить расширение на сайте”;

}

}

function renderCurrentSite(){

currentSiteElement.textContent=

currentHostname || “Не найден”;

updateStatus();

}

function renderSites(){

sitesListElement.innerHTML=””;

if(enabledSites.length===0){

const empty=

document.createElement(“div”);

empty.className=”empty”;

empty.textContent=

“Нет активных сайтов”;

sitesListElement.appendChild(empty);

return;

}

enabledSites.forEach(site=>{

const row=

document.createElement(“div”);

row.className=

“site-row”;

const name=

document.createElement(“div”);

name.className=

“site-name”;

name.textContent=

site;

const button=

document.createElement(“button”);

button.className=

“delete-button”;

button.textContent=

“Удалить”;

button.onclick=

async()=>{

enabledSites=

enabledSites.filter(

item=>

item!==site

);

await saveEnabledSites(

enabledSites

);

renderSites();

renderCurrentSite();

};

row.appendChild(name);

row.appendChild(button);

sitesListElement.appendChild(row);

});

}

async function toggleSite(){

if(!currentHostname){

return;

}

if(isEnabled(currentHostname)){

enabledSites=

enabledSites.filter(

item=>

item!==currentHostname

);

}else{

enabledSites.push(

currentHostname

);

}

await saveEnabledSites(

enabledSites

);

renderSites();

renderCurrentSite();

}

async function addCurrentSite(){

if(!currentHostname){

return;

}

if(!isEnabled(currentHostname)){

enabledSites.push(

currentHostname

);

await saveEnabledSites(

enabledSites

);

}

renderSites();

renderCurrentSite();

}

function bindEvents(){

toggleButton.onclick=

toggleSite;

addButton.onclick=

addCurrentSite;

}

async function init(){

const tab=

await getCurrentTab();

if(!tab){

return;

}

currentHostname=

extractHostname(tab.url);

enabledSites=

await loadEnabledSites();

renderCurrentSite();

renderSites();

bindEvents();

}

document.addEventListener(

“DOMContentLoaded”,

init

);

  1. Сохраняем popup.js

Как начать использовать расширение?

Здесь всё просто:

  • Откройте Chrome и нажмите на «три точки». 
  • Далее — «Расширения», 
  • следующий шаг — «Управление расширениями»
  • И, наконец, — «Загрузить распакованное расширение». Здесь выбираем нашу папку. Убедитесь, что вы включили расширение для конкретного сайта, и всё — наслаждайтесь!

Вместо выводов

Казалось бы, мелочь, а как же приятно.

Зачем терпеть полноэкранные баннеры, из-за которых едва просматривается содержание сайта, если за полчаса можно упростить себе жизнь и сделать использование браузера более комфортным.

Так что, друзья, пробуйте, пользуйтесь — желаем вам больше браузерного комфорта!

  • 2
  • 0
  • 0
18.09.2026
Зарегистрируйся, чтоб оставить комментарий
0
  • По рейтингу
  • По порядку
loading