当前位置: 首页 > 面试题库 >

在已经使用angular的页面上使用Angular in extension

许彭祖
2023-03-14
问题内容

我正在为我的库编写一个Chrome扩展程序(在这里),它的UI使用angular
。它在不使用角度的页面上效果很好,但是会导致确实使用角度的页面出现问题。例如,在“
Angular文档”页面上:

Uncaught Error: [$injector:modulerr] Failed to instantiate module docsApp due to:
  Error: [$injector:nomod] Module 'docsApp' is not available! You either misspelled the module name or forgot to load it. If registering a module ensure that you specify the dependencies as the second argument.
  http://errors.angularjs.org/1.2.7/$injector/nomod?p0=docsApp
at chrome-extension://cfgbockhpgdlmcdlcbfmflckllmdiljo/angular.js:78:14
at chrome-extension://cfgbockhpgdlmcdlcbfmflckllmdiljo/angular.js:1528:19
at ensure (chrome-extension://cfgbockhpgdlmcdlcbfmflckllmdiljo/angular.js:1453:40)
at module (chrome-extension://cfgbockhpgdlmcdlcbfmflckllmdiljo/angular.js:1526:16)
at chrome-extension://cfgbockhpgdlmcdlcbfmflckllmdiljo/angular.js:3616:24
at Array.forEach (native)
at forEach (chrome-extension://cfgbockhpgdlmcdlcbfmflckllmdiljo/angular.js:302:13)
at loadModules (chrome-extension://cfgbockhpgdlmcdlcbfmflckllmdiljo/angular.js:3610:7)
at createInjector (chrome-extension://cfgbockhpgdlmcdlcbfmflckllmdiljo/angular.js:3550:13)
at doBootstrap (chrome-extension://cfgbockhpgdlmcdlcbfmflckllmdiljo/angular.js:1298:22)
http://errors.angularjs.org/1.2.7/$injector/modulerr?p0=docsApp&p1=Error%3A…xtension%3A%2F%2Fcfgbockhpgdlmcdlcbfmflckllmdiljo%2Fangular.js%3A1298%3A22) angular.js:78

奇怪的是,无论我的扩​​展程序是否实际 使用 角度,似乎都发生了。我需要重现该问题的唯一方法是在我的manifest.json中包含angular
content_script并引发此错误。我将如何在不弄乱角度的情况下完成这项工作的任何想法将不胜感激。

就像我说的那样,我是否实际使用角度都无关紧要,但这就是我要做的所有事情:

makeWishForAnchors(); // This just loads the global genie object. I don't believe it's related.

var lamp = '<div class="genie-extension"><div ux-lamp lamp-visible="genieVisible" rub-class="visible" local-storage="true"></div></div>';
$('body').append(lamp);

angular.module('genie-extension', ['uxGenie']);
angular.bootstrap($('.genie-extension')[0], ['genie-extension']);

谢谢!


问题答案:

问题

一旦注入了Angular,它就会解析DOM以寻找带有ng- app指令的元素。如果找到一个,Angular将自动引导。当页面使用Angular本身时,这将成为一个问题,因为(尽管它们具有独立的JS执行上下文)页面和内容脚本共享相同的DOM。

解决方案

您需要防止 您的 角度实例(由“你”我指的是一个由您的分机作为一个内容脚本注入)从自动自举。通常,您只需要忽略该ng- app指令就可以了,但是由于您无法控制原始DOM(也不想破坏页面的功能),因此这不是一个选择。

可以 执行的 操作 是将Angular应用程序的
手动引导 程序与
延迟的引导 程序结合使用(以防止Angular尝试自动引导页面的Angular应用程序)。

同时,您需要从页面的Angular实例中“保护”(即隐藏)应用程序的根元素。为此,您可以使用
ngNonBindable
指令将根元素包装在父元素中,以便页面的Angular实例将其保留下来。

总结以上文档中的步骤,您需要执行以下操作:

  1. 前面加上window.nameNG_DEFER_BOOTSTRAP!之前注入你的角度。
    例如,注入一个angluar.js仅包含一行的小脚本(在之前):

    window.name = 'NG_DEFER_BOOTSTRAP!' + window.name;
    
  2. 将应用程序的根元素包装在具有属性的父元素中ng-non-bindable

    var wrapper = ...    // <div ng-non-bindable></div>
    

    wrapper.appendChild(lamp); // or whatever your root element is
    document.body.appendChild(wrapper);

  3. 在应用程序的主脚本中,手动引导Angular应用程序:

    var appRoot = document.querySelector('#<yourRootElemID');
    

    angular.bootstrap(appRoot, [‘genie-extension’]);

细则: 我尚未亲自测试过,但我保证会尽快进行测试!

更新

以下代码旨在作为上述方法的概念证明。基本上,这是一个演示扩展,每当单击浏览器操作按钮时,它便将Angular支持的内容脚本加载到任何http:/
https:页面中。

扩展会采取所有必要的预防措施,以免干扰(或被页面本身的Angular实例破坏)(如果有)。

最后,我必须添加第三项要求(请参阅上面的更新的解决方案描述),以保护/隐藏内容脚本的Angular应用程序与页面的Angular实例。
(即,我使用
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's 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's 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's 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's 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网页),并且一切似乎都按预期进行。但是,我还没有对这种方法进行彻底的测试!

如果有人感兴趣, 这就是将 “精灵”灯“成角度化”所需要的。



 类似资料:
  • 在运行tomcat进程时,我一直在日志中得到这个绑定异常。它并没有从一开始就禁止我的进程,但这仍然是一个问题。 05-Oct-2017 13:42:47.896严重[main]org.apache.coyote.abstractProtocol.init无法初始化与ProtocolHandler关联的endpoint [“http-nio-*********-不是8080端口”]java.net.

  • null 有什么方法可以在GitHub上使用SharedArrayBuffer吗?我试过上网,但他们对带宽有限制。是否有类似于GitHub的托管静态站点可以允许我们自定义请求头,以便我们可以使用ShareDarrayBuffer?

  • 问题内容: 我发现了几个类似的问题,但是没有一个答案有帮助。它们似乎都涉及某种类型的依赖关系,而我无法正确注入。 我的代码如下: RUN功能 HTML 问题答案: 我的方法很简单。在路由配置中,您可以定义: 然后您监听事件并进行设置。在应用程序运行块中(为此的最佳位置): 这种方法的好处是,它使您可以避免再绑定,这很好。

  • 例如,我的代码中有许多部分使用@event.srcelement...

  • 我想通过量角器运行我的测试用例,但由于一些限制,我希望量角器从一个已经打开的页面开始,这意味着我不希望驱动程序通过加载chrome并转到测试用例中定义的url来启动。如果我可以使用屏幕上已经打开的url,然后进一步处理测试用例中定义的内容,比如单击元素或发送键等,有什么办法吗。 问候赛义德·扎伊迪

  • 问题内容: 如何使用Selenium检查当前页面上是否存在给定的文本字符串? 问题答案: 代码是这样的: