wait for angular app to be fully rendered from pha

2019-03-18 15:50发布

问题:

I'm writing a script which generates png images from every page of my frontend. I'm using angular for the UI and capturing the pages with phantom.

The view take a while until angular finish rendering it so I have to wait a little before capturing:

var page = require('webpage').create();
page.open('http://localhost:9000/', function () {
  window.setTimeout(function () {
    page.render('snapshot.png');
    phantom.exit();
  }, 2000);
});

I wonder if there is a better way to achieve this. I found angular can emit an event when the page is fully rendered:

$scope.$on('$viewContentLoaded', function () {
  // do something
});

And found a way for communicate to phantom with onCallback so I could write something like:

$scope.$on('$viewContentLoaded', function () {
  window.callPhantom({ hello: 'world' });
});

Then in other place in phantom script:

page.onCallback = function() {
  page.render('snapshot.png');
  phantom.exit();
};

But I'm lost in how to inject the angular $viewContentLoaded handle from the phantom script.

I don't know if evaluate/evalueateAsyn are the way to go ...

page.evaluateAsync(function () {
  $scope.$on('$viewContentLoaded', function () {
    window.callPhantom({ hello: 'world' });
  });
});

Maybe I could access the right $scope in some way. Any ideas?

回答1:

The associated PhantomJS API is onCallback; you can find the API doc on the wiki.

// in angular
$scope.$on('$viewContentLoaded', function () {
  window.callPhantom();
});

// in the phantomjs script
var page = require('webpage').create();
page.onCallback = function() {
  page.render('snapshot.png');
  phantom.exit();
};
page.open('http://localhost:9000/');

You can get access to the $rootScope by accessing the injector; for example, if you're using the ng-app directive, you can find the element with the directive and call .injector().get("$rootScope") on it. However, I'm not sure if the $viewContentLoaded event will already have fired by then.