Напишите плагин для хрома для сбора картинок с нуля

внешний интерфейс JavaScript

ноль, введение

В этой статье представлен процесс реализации плагина для браузера Chrome, который в основном включает в себя:

  1. Что такое плагин для браузера
  2. каталог плагинов
  3. Связь с плагином
  4. Отладка плагина
  5. Реализация проекта
  6. Выпуск плагина
  7. Справочная документация

1. Что такое плагин для браузера?

Плагины браузера — это инструменты, добавляющие новые функции на основе исходных функций браузера. Это не независимое программное обеспечение, и для работы его необходимо подключить к соответствующему браузеру. В настоящее время основные браузеры позволяют использовать плагины для улучшения функций браузера и сделать его более разнообразным. Разработка плагина для браузера на самом деле аналогична разработке веб-приложения, состоящего из HTML+JS+CSS.В этой статье будет представлена ​​реализация плагина функции захвата изображения. Этот плагин в основном используется для сбора изображений веб-страниц и их хранения на сервере.

2. Каталог плагинов

Каталог подключаемого модуля браузера Chrome, реализованного в этой статье, показан на следующем рисунке:

2.1 файл manifest.json

В корневом каталоге находится файл manifest.json, в котором содержится список функций и файлов конфигурации всего плагина.Это очень важный и необходимый файл для приложения плагина, и его необходимо поместить в корневой каталог. Среди них манифест_версия, имя и версия являются обязательными, а описание и значки являются рекомендуемыми параметрами.

{	
    "manifest_version": 2, // 清单文件的版本,这个必须写,而且必须是2
    "name": "图片采集", // 插件的名称
    "version": "1.0.0", // 插件的版本
    "description": "这是一个图片采集插件", // 插件描述
    "icons": { // 插件图标
    		"16": "static/img/icon.png"
    		"48": "static/img/icon.png"
        	"128": "static/img/icon.png"
    },
}

2.2 Шаблон страницы

Каталог шаблонов используется для размещения шаблонов страниц, обычно используются popup.html и background.html.

popup.html — это веб-страница окна, которая появляется при нажатии на значок плагина и закрывается сразу после того, как фокус покидает веб-страницу окна, которая используется для взаимодействия с пользователем. В подключаемом модуле коллекции изображений пользователям доступны две кнопки: «Предварительный просмотр всех изображений» и «Показать кнопку захвата».

Укажите страницу pupup через поле default_popup манифеста:

{
	 "browser_action": {
        "default_icon": "static/img/icon.png",
        "default_title": "",
        "default_popup": "template/popup.html"
    },
}

background.html является фоновой страницей и резидентной страницей, ее жизненный цикл самый продолжительный среди всех типов страниц в плагине, она открывается при открытии браузера и закрывается при закрытии браузера, поэтому обычно необходимо Всегда работающий, запускаемый и глобальный код помещается в файл background.html, который можно понимать как фоновый сценарий, который подключаемый модуль запускает в браузере. Например, иногда плагину необходимо взаимодействовать с сервером для выполнения синхронизации данных и других операций, эта операция не воспринимается пользователем, поэтому его можно разместить на фоновой странице для запуска этой части логики.

Укажите фоновую страницу через поле background манифеста:

{
	// 2种指定方式,如果指定JS,那么会自动生成一个背景页
	"page": "template/background.html"
	// "scripts": ["static/js/background.js"]
}

2.3 Статические файлы

В каталоге static размещаются статические файлы, включая изображения, сценарии js и стили css.

icon.png — это значок плагина.

content-script.js — это сценарий js, внедренный подключаемым модулем на веб-страницу. Используя стандартную модель DOM, он может считывать сведения о веб-странице или изменять ее структуру DOM. Связь между веб-страницей и плагин также может быть достигнут через него. В подключаемом модуле коллекции изображений он в основном используется для работы с веб-страницами для получения изображений.

popup.js — это js-скрипт popup.html. В подключаемом модуле захвата изображений главный пользователь собирает сведения о взаимодействии с пользователем и сообщает content-script.js, чтобы он управлял веб-страницей для захвата изображений.

background.js — это js-скрипт background.html. В подключаемом модуле коллекции изображений он в основном используется для хранения собранных изображений на сервере.

content-script.css — это стиль CSS, который подключаемый модуль внедряет на веб-страницу.

content-script можно внедрить через конфигурацию манифеста:

{
	"content_scripts": [{
        "matches": ["<all_urls>"], // <all_urls> 表示匹配所有地址
        "js": ["static/js/jquery-1.8.3.js", "static/js/content-script.js"], // 多个js顺序注入
        "css": ["static/css/content-script.css"], //css注入
        "run_at": "document_end" // 代码注入的时间,可选值: document_start, document_end, or document_idle,最后一个表示页面空闲时,默认document_idle
    }]
}

3. Подключаемый модуль связи

3.1 Связь контекста плагина

И popup.js, и background.js запускаются в контексте плагина.Поскольку они запускаются в одном потоке, связь между ними относительно проста, и страницы могут напрямую вызывать методы друг друга для передачи информации. Например, метод chrome.extension.getViews() может возвращать список оконных объектов, принадлежащих каждой активной странице вашего плагина, а метод chrome.extension.getBackgroundPage() может возвращать фоновую страницу.

// background.js
var views = chrome.extension.getViews({type:'popup'}); // 返回popup对象
if(views.length > 0) {
    console.log(views[0].location.href);
}
function test(){
	console.log('我是background');
}

// popup.js
var bg = chrome.extension.getBackgroundPage();
bg.test(); // 访问background的函数
console.log(bg.document.body.innerHTML); // 访问background的DOM

3.2 контент-скрипт взаимодействует с контекстом плагина

content-script.js — это скрипт, встроенный в веб-страницу, поэтому он фактически работает в контексте веб-страницы и полностью изолирован от контекста плагина.Нет возможности вызывать методы для взаимодействия друг с другом, как страницы связаны с контекстом плагина. Для облегчения связи требуется канал связи. В подключаемом модуле сбора изображений content-script.js получает сообщения от popup.js для сбора изображений веб-страниц и отправляет сообщения в background.js для хранения изображений.

popup.js или background.js активно отправляет сообщение в content-script.js:

function sendMsgToContentScript(message, callback){
	chrome.tabs.query({active: true, currentWindow: true}, function(tabs){
		chrome.tabs.sendMessage(tabs[0].id, message, function(response){
			if(callback) callback(response);
		})
	})
}

sendMsgToContentScript({type: 'popMsg', value: '你好, 我是popup'}, function(response){
	console.log('来自content的回复:' + response);
})

content-script.js получает сообщение:

chrome.runtime.onMessage.addListener(function(request, sender, sendResponse){
	if(request.type === 'popMsg'){		console.log('收到来自popup的消息:' + request.value);
	}
	sendResponse('我是content-script,已收到你的消息');
})

content-script.js заранее отправляет сообщение в popup.js или background.js:

chrome.runtime.sendMessage({type: 'contentMsg', value: '你好,我是content-script'},function(response){
	console.log('收到来自后台的回复:'+ response);
})

popup.js и background.js получают сообщение:

	chrome.runtime.onMessage.addListener(function(request, sender, sendResonse){
		console.log()
		if(request.type === 'contentMsg'){
			console.log('收到来自content-script的消息:' + request.value);
		}
		sendResonse('我是后台,已收到你的消息。');
	})

Следует отметить, что предпосылкой активной отправки сообщений в popup.js из content-script.js является то, что страница всплывающего окна должна быть открыта, в противном случае background.js необходимо использовать в качестве реле.

В-четвертых, отладка плагинов

4.1 Установите комплект разработки плагинов

1. Откройте страницу управления плагинами. Войдите на страницу управления плагинами через меню браузера или напрямую введите chrome://extensions в адресной строке для доступа.

2. Проверьте режим разработчика. После проверки можно напрямую загрузить папку приложения плагина, иначе может быть установлен только сжатый файл в формате .crx, а обновление плагина не синхронизируется по времени.

3. Обновление плагина. Любые изменения в коде в процессе разработки требуют перезагрузки плагина, просто нажмите кнопку обновления плагина, на всякий случай лучше также обновить страницу.

4.2 Отладка содержимого-script.js

content-script.js — это скрипт, который запускается на веб-странице, и вы можете отладить его, открыв инструменты разработчика веб-страницы.

4.3 Отладка background.js

Поскольку background.js и content-script.js не работают в одном контексте, окно отладки веб-страницы не может видеть background.js. Для отладки background.js необходимо открыть окно отладки плагина. На странице управления подключаемым модулем щелкните "Просмотреть шаблон представления/background.html" вашего подключаемого модуля, и появится окно отладки подключаемого модуля. Следующая операция аналогична обычной отладке веб-страницы.

4.4 Отладка popup.js

Хотя popup.js и background.js находятся в одном контексте, если вы хотите увидеть popup.js, вам нужен еще один шаг, чтобы «щелкнуть, чтобы просмотреть содержимое всплывающего окна»:

5. Реализация проекта

5.1 Реализация веб-страницы с всплывающим окном

Веб-страница всплывающего окна предоставляет пользовательский интерфейс, который в основном включает следующие функции:

  • Когда пользователь нажимает кнопку «Предварительный просмотр всех загруженных изображений», popup.js уведомляет content-script.js о необходимости прочитать DOM веб-страницы, отфильтровать DOM изображения и удалить ссылку на изображение. Затем используйте DOM, чтобы создать диалоговое окно на веб-странице, и поместите все изображения в диалоговое окно для централизованных операций предварительного просмотра и сбора.
  • Пользователь переключает флажок «Отображает ли страница кнопку захвата изображения». Если этот флажок установлен, popup.js уведомит сценарий контента о необходимости управлять DOM веб-страницы и добавит кнопку захвата к изображению. Если этот флажок не установлен, popup.js уведомит скрипт содержимого об удалении кнопки захвата на веб-странице.

<!-- popup.html -->
<div>
  	<div id="preViewAllImg">
      <img src="https://s10.mogucdn.com/mlcdn/c45406/190219_4949lfk7le758fei1825i6dkd4g9i_40x42.png" />预览全部已加载图片
  	</div>
  	<div class="collect_btn_wrap" id="showCollectBtn">
      	<div class="collect_btn">
          <div class="show_collect_check"><img class="collect_check_img" src="" /></div>页面显示收藏按钮
      	</div>
	 </div>
</div>
<script type="text/javascript" src="../static/js/jquery-1.8.3.js"></script>
<script type="text/javascript" src="../static/js/popup.js"></script>

<!-- popup.js -->
$(function () {

    function sendMsgToContentScript(message, callback){
        chrome.tabs.query({active: true, currentWindow: true}, function(tabs){
            chrome.tabs.sendMessage(tabs[0].id, message, function(response){
                if(callback) callback(response);
            })
        })
    }

    // 一键收集全部图片
    $('#preViewAllImg').click(e => {
        sendMsgToContentScript({type: 'REQUEST_PREVIEW_ALL_IMG', title: '我是popup, 请采集所有已加载图片并进行预览'}, function(response){
            console.log('我是popup, 来自content的回复:' + response);
        });
    });

    // 是否显示采集按钮
    $('#showCollectBtn').click(() => {
        var src = $('.collect_check_img').attr('src');
        var status = src === ''; // status: true 显示
        $('.collect_check_img')[0].src = src === '' ? 'https://s10.mogucdn.com/mlcdn/c45406/190219_0728g95i8bkl3i08jic6lhjhh7gae_24x18.png' : '';

        // 向content-script发送消息显示or隐藏单个商品的收藏按钮
        sendMsgToContentScript({type: 'REQUEST_SWITCH_COLLECT_BTN', title: `我是popup, 请${status?'显示':'隐藏'}采集按钮`, status}, function(response){
                console.log('我是popup, 来自content的回复:' + response);
        });
    });
})

5.2 Реализация сценария вставки содержимого-скрипта

content-script будет прослушивать сообщения от popup.js, управлять DOM веб-страницы в соответствии с уведомлением о сообщении, выполнять такие операции, как чтение ссылок на изображения, добавление кнопок захвата изображений, захват изображений и т. д., а также отправка сообщения на фон, чтобы уведомить его о сохранении захваченных ссылок на изображения.

<!-- content-script.js -->
chrome.runtime.onMessage.addListener(function (request, sender, sendResponse) {
    if(request.type === 'REQUEST_PREVIEW_ALL_IMG'){

        console.log('我是content-script,收到来自popup的消息:' + request.title);

        sendResponse('我是content-script, 已收到你的预览全部图片的消息');

        PreviewAllImg();

    }else if(request.type === 'REQUEST_SWITCH_COLLECT_BTN'){

        console.log('我是content-script,收到来自popup的消息:' + request.title);

        sendResponse(`我是content-script, 已收到你${request.status ? '显示':'隐藏'}采集按钮的消息`);

        if(request.status){
            ShowCollectBtn();
        }else{
            ClearCollectBtn();
        }
    }else if(request.type === 'COLLECT_RESULT'){
        console.log('我是content-script,收到来自background的消息:' + request.title);
        sendResponse(`我是content-script, 已收到你的${request.title}的消息`);
    }
});


// 预览所有已加载图片
function PreviewAllImg(){
    GetAllAttrList('img', ['src', 'data-src']).then((res) => {
        ShowImgPanel(res);
    })
}

// 展示采集按钮
function ShowCollectBtn(){
    $('img').each((index, item) => {
        let src = $(item).attr('src') || $(item).attr('data-src');
        $($(item).parent()).css('position', 'relative');
        $($(item).parent()).find('.collect_img_btn').remove();
        $($(item).parent()).append('<div class="collect_img_btn" data-src="'+src+'">采集</div>');

    });
    $('.collect_img_btn').click((e) => {
        e.stopPropagation();
        e.preventDefault();
        let src = $(e.target).data('src');
        chrome.runtime.sendMessage({type: 'SEND_IMG', src: src},function(response){
            console.log('我是content-script, 收到来自后台的回复:' + response);
        })
    });
}

// 清除采集按钮
function ClearCollectBtn(){
    $('.collect_img_btn').remove();
}

// 展示预览图片对话框
function ShowImgPanel(list){
    var panelDOM = $('<div id="collect_img_panel">' +
            '<div class="collect_img_panel_close">x</div>' +
            '<div class="collect_img_panel_content">x</div>' +
            '</div>');
        $('body').append(panelDOM);
        $('body').append('<div id="collect_img_panel_mask"></div>');
        let $item = '';
        $.each(list, function(index, item) {
            $item = $item + '<div class="collect_img_panel_item">' +
                '<div class="collect_img_panel_item_img" style="background-image: url(' + item + ')"></div>' +
                '<div class="collect_img_panel_item_mask"></div>' +
                '<div class="collect_img_panel_item_btn" data-src="'+ item+'">采集图片</div>' +
                '</div>';
        });
        $('.collect_img_panel_content').html($item);
        $('.collect_img_panel_item_btn').click((e)=>{
            let src = $(e.target).data('src');
            chrome.runtime.sendMessage({type: 'SEND_IMG', src: src},function(response){
                console.log('我是content-script, 收到来自后台的回复:' + response);
            })
        });
        $(".collect_img_panel_close").click(function() {
            $('#collect_img_panel').remove();
            $('#collect_img_panel_mask').remove();
        });
}

// 根据标签和属性采集所有符合条件的对象
function GetAllAttrList(obj, attrArr){
    return new Promise((resolve) => {
        let list = [];
        $(obj).each((index, item) => {
            GetAttrContent(item, attrArr).then(res => {
                list.push(res);
                if(index === $(obj).length - 1){
                    resolve(list);
                }
            });
        });
    });
}

// 获取对象的属性内容
function GetAttrContent(obj, attrArr){
    return new Promise((resolve) => {
        $.each(attrArr, (attrIndex, attrItem) => {
            let attrContent = $(obj).attr(attrItem);
            if(attrContent){
                resolve(attrContent);
            }
        })
    });
}

5.3 Фоновая реализация фоновой страницы

Фоновая фоновая страница прослушивает сообщения от скрипта содержимого и сохраняет собранные изображения на сервере.

<!-- background.html -->
<div>
     <script type="text/javascript" src="../static/js/jquery-1.8.3.js"></script>
     <script type="text/javascript" src="../static/js/background.js"></script>
 </div>
 
<!--background.js-->
chrome.runtime.onMessage.addListener(function (request, sender, sendResponse) {
    if(request.type === 'SEND_IMG'){
        alert('我是background,采集到图片链接:' + request.src);

        sendResponse('正在采集图片');
        requestStoreImg(request.src);
    }
});

// 存储图片
function requestStoreImg(src) {

		$.ajax({
            type: 'get',
            url: 'https:/www.mogu.com/*/store',
            data: {
                url: src
            },
            success: function(res) {
                if (res.status && res.status.code && res.status.code === 1001) {
                		sendMsgToContentScript({type: 'COLLECT_RESULT', title: '图片采集成功'}, function(response){
    				            alert('我是background,来自content的回复:' + response);
    				        });
                } else {
                    sendMsgToContentScript({type: 'COLLECT_RESULT', title: '图片采集失败'}, function(response){
    				            alert('我是background,来自content的回复:' + response);
    				        });
                }
            },
            error: function(res){
            			sendMsgToContentScript({type: 'COLLECT_RESULT', title: '接口异常采集失败'}, function(response){
    				            alert('我是background,来自content的回复:' + response);
    			        });
            }
        })
}

function sendMsgToContentScript(message, callback){
    chrome.tabs.query({active: true, currentWindow: true}, function(tabs){
        chrome.tabs.sendMessage(tabs[0].id, message, function(response){
            if(callback) callback(response);
        })
    })
}

6. Выпуск плагина

После завершения разработки пакет .crx упаковывается и генерируется через «Расширение пакета» на странице плагина.

Войдите с помощью учетной записи GoogleПанель разработчика, Заполните всю необходимую информацию, и вы можете опубликовать ее.

7. Справочные документы

developer.chrome.com/extensions open.chrome.360.capable/extension_…