Този урок е базиран на манифеста на разширението на chrome версия 3 (MV3), а също и на Angular версия 2+ (2, 3 и...). Ако не сте използвали манифест версия 3, можете да следвате този урок, за да мигрирате от манифест V2 към V3.

В края на тази статия ще можете да демонстрирате приложението си Angular в изскачащ прозорец на разширението на Chrome или в диалогов прозорец (като използвате iframe, който се стартира от скриптов файл със съдържание на разширение за хром).

Конфигурации на приложение Angular

Първо, създайте и разработете вашето желано Angular приложение, както искате. Това означава, че когато разработвате приложение на Angular, не мислете за никаква конфигурация, свързана с разширението на chrome, а разработвайте приложението си както винаги.

След като завършите разработката на вашето Angular приложение, имате нужда само от 2 промени, за да подготвите вашето Angular приложение за внедряване в разширението на хром.

  1. Променете “base href” на приложението в приложението Angular index.html.
<base href="/app/index.html">

Пълен изглед на приложението Angular index.html:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>Application Title</title>

    <!--   <base href="/" />   --> // Remove this 
    <base href="/app/index.html"> // Use this instead of the above line

    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <link rel="icon" type="image/x-icon" href="favicon.ico" />
</head>
<body>
<app-root></app-root>
</body>
</html>

Ще обясня значението на „/app/index.html“ в следващите части на тази статия.

2. Добавете следната конфигурация към вашата конфигурация за маршрутизиране на Angular приложение.

useHash: true

Пълен изглед на конфигурацията за маршрутизиране:

RouterModule.forRoot(routes, { useHash: true })

Сега трябва да изградим нашето Angular приложение и да генерираме папката dist, като изпълним тази команда в терминала на директорията на проекта на Angular приложение.

ng build --prod

Досега научаваме как да конфигурираме приложението Angular, за да може да се разгръща в разширението на chrome.

Следващата стъпка ще ни покаже как да използваме приложението Angular в разширението на chrome.

Конфигурации на разширения за Chrome

На първо място, заслужава да се отбележи, че този урок е базиран на манифест на разширението на chrome версия 3 (MV3).

Къде искаме да демонстрираме нашето Angular приложение в нашето разширение за Chrome?Изскачащ прозорец на разширението за Chromeили диалогов прозорец(използвайки iframe)?

За по-добро разбиране вижте изображенията по-долу, като първото е свързано с приложението Angular в изскачащия прозорец на разширението на chrome, а второто е свързано с приложението Angular в iframe на разширението на chrome.

Сега нека обясним всеки един стъпка по стъпка.

Използвайте изскачащия прозорец на разширението на Chrome, за да покажете приложението Angular

  1. Създайте папка в главната директория на проекта за разширение на chrome и я наименувайте app,и след това копирайте и поставете вашите компилирани файлове на Angular приложение от dist папка вътре в него. Имайте предвид, че за да поставите само съдържанието на папката dist на приложението Angular.
    Вижте структурата на директорията на проекта по-долу.
Sample Extension Project Directory

-- app
   - index.html
   .
   .
   .
-- assets
   - cancel.png
   - icon.png
-- popup
   - popup.js 
   - popup.html
   - popup.css
-- background.js
-- content_script.js
-- manifest.json

2. Конфигурационен файл manifest.json.

"manifest_version": 3,
"name": "Angular App",
"version": "1.0.1",
.
.
.
"action": {
  "default_icon": "assets/icon.png",
  "default_title": "Angular App",
  "default_popup": "app/index.html" // Please, look at the path carefully!
},
.
.
.
"web_accessible_resources": [
  {
    "resources": [
      "app/index.html"
      .
      .
      .
    ]
  }
]

Това е всичко и сега можете да гледате приложението си Angular в изскачащия прозорец на разширението на chrome.

Използвайте диалогов прозорец (iframe), за да покажете приложението Angular

При този подход ще създадем iframe вътре в скриптовия файл със съдържание на разширението на chrome и след това ще добавим нашето Angular приложение към този iframe, за да видим нашето приложение в диалогов прозорец (модален) на екрана.

За да реализирам това, предпочитам да създам функция за отваряне и затваряне на диалоговия прозорец (модал) с уникален идентификатор. Така че с тази функция можете да създавате и показвате колкото желаете диалогови прозорци един на друг и всеки от тях има уникален идентификатор.

  1. Създайте функция openDialog() във файла content_script.js. Тази функция ще получи 3 аргумента:
  • id: Уникалният идентификатор на диалоговия прозорец.
  • опции: Персонализираните опции, които искате да бъдат зададени в диалоговия прозорец.
  • contentPath: Пътят на първоначалния маршрут на приложението Angular, който иска да се покаже веднага след отваряне на диалоговия прозорец. Имайте предвид, че за да напишете първоначалния маршрут на приложението Angular след пътя на директорията на приложението Angular вътре в проекта за разширение на chrome. Например, ако файловете за компилация на приложението Angular (съдържанието на папката dist) са под папката app в основната директория на разширението на chrome, тогава contentPathще изглежда така : “app/index.html#/”. Или, ако искате да отворите конкретен маршрут на приложението Angular (напр. /store), тогава contentPathна “/store” (пътят на Angular route да бъде показан вътре в диалоговия прозорец) ще изглежда така: “app/index.html#/store”.
const preModalContainerId = '_container-';

function openDialog(id, options, contentPath) {

    // First load dialog html file
    getHtmlContent(contentPath).then(modalHtmlContent => {

        // Create dialog overlay (a black layer behind the dialog body)
        const overlayElem = document.createElement("div");
        overlayElem.classList.add('myext-modal-overlay');
        overlayElem.setAttribute("id", id);

        // Create an iframe for showing dialog body (in Chrome extension the dialog should be used with iframe)
        const iframeElement = document.createElement("iframe");

        // Check if options has iframe class name for styling
        if (options?.iframe?.className) {
            iframeElement.classList.add(options.iframe.className);
        } else {
            iframeElement.setAttribute("style", "width: 100%; height: 100%;");
        }

        // Assign src for iframe to show Angular app
        iframeElement.src = chrome.runtime.getURL(contentPath);

        // If overlay has cancel button then prepare to clear iframe from screen by click on cancel icon
        if (options?.overlay?.hasCancelBtn) {
            const cancelButton = document.createElement("span");

            // if options has cancel button class name for styling
            if (options?.overlay?.cancelBtnImage) {
                cancelButton.style.backgroundImage = 'url(' + getAssetImgPath(options.overlay.cancelBtnImage) + ')';
            } else {
                cancelButton.innerText = '+';
            }

            // if options has cancel button class name for styling
            if (options?.overlay?.cancelBtnClassName) {
                cancelButton.classList.add(options.overlay.cancelBtnClassName);
            } else {
                cancelButton.classList.add('myext-modal-overlay-cancel-btn');
            }

            overlayElem.appendChild(cancelButton);

            jq(cancelButton).click(() => {
                closeDialog(id);
            });
        }

        // Set iframe as dialog overlay child
        overlayElem.appendChild(iframeElement);

        // Dialog body container
        const modalBodyContainerId = preModalContainerId + id;
        const modalBodyContainer = document.createElement("div");
        modalBodyContainer.classList.add('myext-modal-container');
        modalBodyContainer.setAttribute("id", modalBodyContainerId);

        // Add dialog html file content to dialog body container
        modalBodyContainer.innerHTML = modalHtmlContent;

        document.body.appendChild(overlayElem);
        document.body.appendChild(modalBodyContainer);
    });
}

function getAssetImgPath(assetPath) {
    return chrome.runtime.getURL(assetPath);
}

Константната променлива preModalContainerId беше създадена и добавена към началото на уникалния идентификатор на контейнера на диалоговия прозорец, за да се предотврати всеки конфликт с всяко друго разширение на chrome, което ще отвори вградена рамка на екрана едновременно.

Функцията getHtmlContent(contentPath)вътре във функцията openDialog() е функция слушател за извикване и зареждане на Първоначалният маршрут на приложението Angular и връщане на HTMLсъдържанието, както е показано по-долу:

async function getHtmlContent(htmlFileUrl) {
    let fileUrl;

    // Check if html file url is decoded or not
    if (htmlFileUrl.includes('chrome-extension://')) {
        fileUrl = htmlFileUrl;
    } else {
        fileUrl = chrome.runtime.getURL(htmlFileUrl);
    }

    return await (await fetch(fileUrl)).text();
}

2. Създайте функция closeDialog() във файла content_script.js. Тази функция ще получи 1 аргумент:

  • id: Уникалният идентификатор на диалоговия прозорец, който трябва да бъде затворен.
function closeDialog(id) {
    const overlayElem = document.getElementById(id);
    const modalBodyContainerId = preModalContainerId + id;
    const modalBodyContainer = document.getElementById(modalBodyContainerId);

    if (overlayElem) overlayElem.remove();
    if (modalBodyContainer) modalBodyContainer.remove();
}

3. Създайте файл style.css в главната директория на проекта за разширение на chrome и поставете следните кодове вътре в него. Можете да промените всеки от тях според нуждите.

.myext-modal-overlay {
    display: inline-block;
    position: fixed;
    width: 100%;
    height: 100%;
    left: 0;
    top: 0;
    background: rgba(51, 51, 51, 0.7);
    z-index: 1000000;
}

.myext-modal-overlay-cancel-btn {
    position: absolute;
    width: 50px;
    height: 50px;
    left: 50px;
    top: 50px;
    font-size: 2.5em;
    color: white;
    background-color: #c57070;
    border-radius: 50%;
    display: flex;
    justify-content: center;
    align-items: center;
    transform: rotate(45deg);
    cursor: pointer;
    z-index: 1001;
    transition: all 0.25s ease-in-out;
}

.myext-modal-overlay-cancel-btn:hover {
    background-color: #b06565;
    box-shadow: 0 2px 10px #666;
}

.myext-modal-container {
    display: block;
    position: fixed;
    border-radius: 18px;
    overflow: hidden;
    box-shadow: 0 2px 50px #444;
    background: #1d222f;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    z-index: 2001;
}

.myext-iframe {
    position: fixed;
    border-radius: 35px;
    overflow: hidden;
    box-shadow: 0 2px 50px #444;
    top: 50px;
    right: 50px;
    height: 630px;
    width: 390px;
}

.myext-modal-overlay-custom-cancel-btn {
    position: absolute;
    width: 50px;
    height: 50px;
    top: 35px;
    right: 35px;
    border-radius: 50%;
    background-repeat: no-repeat;
    object-fit: cover;
    background-size: cover;
    display: flex;
    justify-content: center;
    align-items: center;
    cursor: pointer;
    z-index: 1001;
    transition: all 0.25s ease-in-out;
}

.myext-modal-overlay-custom-cancel-btn:hover {
    box-shadow: 0 2px 10px #666;
}

4. Конфигурационен файл manifest.json.

"manifest_version": 3,
"name": "Angular App",
"version": "1.0.1",
.
.
.
"content_scripts": [
  {
    "matches": [
      "<all_urls>"
    ],
    "js": [
      "content_script.js",
    ],
    "css": [
      "style.css"
    ],
    "run_at": "document_end",
    "all_frames": false
  }
],
"action": {
  "default_icon": "assets/icon.png",
  "default_title": "Angular App",
  "default_popup": "app/index.html" // Please, look at the path carefully!
},
.
.
.
"web_accessible_resources": [
  {
    "resources": [
      "app/index.html"
      "style.css",
      .
      .
      .
    ],
    "matches": [
      "<all_urls>"
    ]
  }
]

Сега можете да извикате функцията openDialog(), за да създадете и покажете първия си диалог на екрана, както е показано по-долу:

const dialogOptions = {
    iframe: {
        className: 'myext-iframe'
    },
    overlay: {
        hasCancelBtn: true,
        cancelBtnClassName: 'myext-modal-overlay-custom-cancel-btn',
        cancelBtnImage: 'assets/images/cancel-btn.png'
    }
}

openDialog('example-id', dialogOptions, 'app/index.html#/');

Освен това можете да затворите горния диалог по следния начин:

closeDialog('example-id');

Заключение

Сега можете да демонстрирате своето Angular приложение или в изскачащ прозорец на разширението на Chrome, или в диалогов прозорец (чрез използване на iframe, който се стартира от скриптов файл със съдържание на разширение на Chrome ).

Благодаря ви много, че прочетохте тази статия.