Migrate from jsdom to phantomJS ? (basic DOM creat

2019-02-18 04:36发布

问题:

M. Bostock pointed out that nodejs' jsdom have incomplete support for svg, and, critical for me, doesn't support getBBox(). Also, he advised to switch to nodejs' PhantomJS. I checked out but the approach is new to me.

My nodejs + jsdom script create a virtual DOM, with which my d3js plays and is as follow :

var jsdom = require('jsdom');
jsdom.env(                             // creates virtual page
  "<html><body></body></html>",        // create my DOM hook,
  [ 'http://d3js.org/d3.v3.min.js',    // add my online dependencies ...
  '../js/d3.v3.min.js',                // ... & local ones
  '../js/jquery-2.1.3.min.js'],

  function (err, window) {
           //my normal JS or nodejs code here !
  }
);

How to migrate this nodejs + jsdom into nodejs + PhantomJS ?

回答1:

Since you want to do this from node.js, you should use a PhantomJS bridge like phantomjs-node (phantom npm module).

When you don't open a page in PhantomJS, you're actually working in an about:blank page, you need to add '--local-to-remote-url-access=yes' commandline option for the underlying PhantomJS process, so that remote resources can be loaded. Maybe --web-security=false, --ssl-protocol=any and ignore-ssl-errors=true may be necessary.

To inject additional scripts into the DOM, you need to use injectJs() for local files and includeJs() for remote files. Furthermore, you cannot directly access the DOM in PhantomJS, because it has two contexts. The sandboxed page context (page.evaluate()) has no access to variables defined outside, so you will need to pass them explicitly in, if you need them.

var phantom = require('phantom');
var async = require('async');

function run(page, ph) {
    page.evaluate(function () {
        // page context: DOM code here
        return document.title;
    }, function (title) {
        // node code here
        console.log('Page title is ' + title);
        ph.exit();
    });
}

var remoteScripts = [ "http://d3js.org/d3.v3.min.js" ];
var localScripts = [ "../js/d3.v3.min.js", "../js/jquery-2.1.3.min.js" ];
phantom.create('--local-to-remote-url-access=yes', '--web-security=false', function (ph) {
    ph.createPage(function (page) {
        async.series(remoteScripts.map(function(url){
            return function(next){
                page.includeJs(url, function(){
                    next();
                });
            };
        }), function(){
            async.series(localScripts.map(function(url){
                return function(next){
                    page.injectJs(url, function(){
                        next();
                    });
                };
            }), function(){
                run(page, ph);
            });
        });
    });
});

You can use async to load script lists into the DOM. I used the series() function.