How to use angularjs with greasemonkey to modify web pages?

后端 未结 1 1736
后悔当初
后悔当初 2021-02-06 11:21

I want to modify web pages\' behavior using angularjs and greasemonkey. I want to know, what\'s the best way to do it? Should I use jquery to inject attributes like \"ng-*

相关标签:
1条回答
  • 2021-02-06 12:06

    There's a general answer about dynamically modifying AngularJS content in the DOM from JavaScript code here:

    AngularJS + JQuery : How to get dynamic content working in angularjs

    To sum up, when you put ng-* attributes into the DOM from JavaScript code, they won't automatically get hooked up; but AngularJS provides the $compile function for hooking up new HTML content with AngularJS attributes from JavaScript.

    So what does this mean when it comes to Greasemonkey/Userscript?

    For the purposes of this I'm assuming that your Greasemonkey script is modifying an existing page that already uses AngularJS, and the AngularJS content you want to add uses some of the variables or functions in AngularJS scopes already on that page.

    For those purposes:

    1. Get a reference to $compile from AngularJS' dynamic injection system
    2. Get a reference to the AngularJS scope that you want your HTML code to be connected to
    3. Put your HTML code with ng-* attributes in a string and call $compile on it and the scope.
    4. Take the result of that and put it into the page using the usual jQuery-style ways.

    To illustrate, here's a little script for CERN's Particle Clicker game, which adds a stat under the 'workers' section.

    $(function () { // Once the page is done loading...
    
       // Using jQuery, get the parts of the page we want to add the AngularJS content to
       var mediaList = $('ul.media-list');      
       var medias = $('li.media', mediaList);
    
       // A string with a fragment of HTML with AngularJS attributes that we want to add.
       // w is an existing object in the AngularJS scope of the
       // <li class="media"> tags that has properties rate and cost.
       var content = '<p>dps/MJTN = <span ng-bind="w.rate / w.cost * 1000000 | number:2"></span></p>';
    
       // Invoke a function through the injector so it gets access to $compile **
       angular.element(document).injector().invoke(function($compile) {
    
           angular.forEach(medias, function(media) {
    
               // Get the AngularJS scope we want our fragment to see
               var scope = angular.element(media).scope();
    
               // Pass our fragment content to $compile,
               // and call the function that $compile returns with the scope.
               var compiledContent = $compile(content)(scope);
    
               // Put the output of the compilation in to the page using jQuery
               $('p', media).after(compiledContent);
    
           });
       });
    
    });
    

    ** NB: Like any AngularJS function that uses its dependency injection, .invoke uses the parameter names of the function you pass to it determine what to inject, and this will break if you're using a minifier that changes the parameter names.

    To avoid this you can replace

    .invoke(function($compile) { ... });
    

    with the form

    .invoke(['$compile', function($compile) { ... }]);
    

    which won't break if the minifier changes the parameter name to something other than $compile.

    0 讨论(0)
提交回复
热议问题