Ответ 1
Проблема
Как только вводится Angular, он анализирует DOM, ища элемент с директивой ng-app
. Если вы обнаружите, что Angular автоматически загрузится. Это становится проблемой, когда страница использует Angular сама, потому что (хотя они имеют отдельные контексты JS-исполнения), страница и контент script имеют один и тот же DOM.
Решение
Вам нужно предотвратить ваш экземпляр Angular ( "ваш", я имею в виду тот, который был добавлен вашим расширением в качестве содержимого script), из автоматической начальной загрузки. Обычно вы просто опускаете директиву ng-app
, и вам было бы хорошо идти, но поскольку вы не имеете контроля над исходным DOM (и не хотите нарушать функциональность страницы), это не вариант.
Что вы можете использовать ручную загрузку для вашего приложения Angular в сочетании с отложенная загрузкa > (чтобы ваша программа Angular пыталась автоматически загружать страницу Angular).
В то же время вам нужно "защитить" (т.е. скрыть) свой корневой элемент приложения на странице Angular. Для этого вы можете обернуть свой корневой элемент в родительский элемент директивой ngNonBindable, поэтому экземпляр Angular будет оставьте это в покое.
Подводя итоги шагам из вышеуказанных документов, вам необходимо сделать следующее:
-
Подготовьте
window.name
с помощьюNG_DEFER_BOOTSTRAP!
перед вводом вашего Angular.
Например. введите script (доangluar.js
), содержащий только одну строку:window.name = 'NG_DEFER_BOOTSTRAP!' + window.name;
-
Оберните свой корневой элемент приложения в родительском элементе с атрибутом
ng-non-bindable
:var wrapper = ... // <div ng-non-bindable></div> wrapper.appendChild(lamp); // or whatever your root element is document.body.appendChild(wrapper);
-
В главном приложении script вручную загрузите приложение Angular:
var appRoot = document.querySelector('#<yourRootElemID'); angular.bootstrap(appRoot, ['genie-extension']);
<суб > Точная печать: Я сам ее не тестировал, но я обещаю сделать это скоро!
Суб > удаp >
UPDATE
Приведенный ниже код предназначен для доказательства концепции описанного выше подхода. В принципе, это демонстрационное расширение, которое загружает Angular -powered content- script на любую страницу http:
/https:
всякий раз, когда нажимается кнопка действия браузера.
Расширение принимает все необходимые меры предосторожности, чтобы не мешать (или не разбиваться) на странице собственный экземпляр Angular (если есть).
Наконец, мне пришлось добавить третье требование (см. выше описание выше), чтобы защитить/скрыть приложение content-script Angular со страницы Angular.
(I.e. Я обернул корневой элемент в родительском элементе директиву ngNonBindable.)
manifest.json:
{
"manifest_version": 2,
"name": "Test Extension",
"version": "0.0",
"background": {
"persistent": false,
"scripts": ["background.js"]
},
"browser_action": {
"default_title": "Test Extension"
// "default_icon": {
// "19": "img/icon19.png",
// "38": "img/icon38.png"
// },
},
"permissions": ["activeTab"]
}
background.js:
// Inject our Angular app, taking care
// not to interfere with page Angular (if any)
function injectAngular(tabId) {
// Prevent immediate automatic bootstrapping
chrome.tabs.executeScript(tabId, {
code: 'window.name = "NG_DEFER_BOOTSTRAP!" + window.name;'
}, function () {
// Inject AngularJS
chrome.tabs.executeScript(tabId, {
file: 'angular-1.2.7.min.js'
}, function () {
// Inject our app script
chrome.tabs.executeScript(tabId, {file: 'content.js'});
});
});
}
// Call `injectAngular()` when the user clicks the browser-action button
chrome.browserAction.onClicked.addListener(function (tab) {
injectAngular(tab.id);
});
content.js:
// Create a non-bindable wrapper for the root element
// to keep the page Angular instance away
var div = document.createElement('div');
div.dataset.ngNonBindable = '';
div.style.cssText = [
'background: rgb(250, 150, 50);',
'bottom: 0px;',
'font-weight: bold;',
'position: fixed;',
'text-align: center;',
'width: 100%;',
''].join('\n');
// Create the app root element (everything else should go in here)
var appRoot = document.createElement('div');
appRoot.dataset.ngController = 'MyCtrl as ctrl';
appRoot.innerHTML = 'Angular says: {{ctrl.message}}';
// Insert elements into the DOM
document.body.appendChild(div);
div.appendChild(appRoot);
// Angular-specific code goes here (i.e. defining and configuring
// modules, directives, services, filters, etc.)
angular.
module('myApp', []).
controller('MyCtrl', function MyCtrl() {
this.message = 'Hello, isolated world !';
});
/* Manually bootstrap the Angular app */
window.name = ''; // To allow `bootstrap()` to continue normally
angular.bootstrap(appRoot, ['myApp']);
console.log('Boot and loaded !');
<суб > Точная печать:
Я провел несколько предварительных тестов (с веб-страницами Angular и не Angular), и все работает так, как ожидалось. Тем не менее, я никоим образом не проверял этот подход!
Суб >
Если кто-то заинтересован, это то, что нужно, чтобы "Angularize" Genie lamp.