Содержимое нижнего колонтитула не работает

Я пытаюсь создать собственные нижние колонтитулы, например, в примерах phantomjs: https://github.com/ariya/phantomjs/blob/master/examples/printheaderfooter.js

Вот мой код:

var phantom = require('node-phantom');

phantom.create(function (err, ph) {
    ph.createPage(function (err, page) {
         page.set('paperSize', {
              format: 'A4',
              orientation: 'portrait',
              footer: {
                contents: ph.callback(function (pageNum, numPages) {
                  if (pageNum == 1) {
                    return "";
                  }
                  return "<h1>Header <span style='float:right'>" + pageNum + " / " + numPages + "</span></h1>";
                })
              }
         }, function () {
             page.open('http://www.google.com', function () {
              })
         })
    })
});

Но, к сожалению, я получаю следующую ошибку:

TypeError: Object #<Object> has no method 'callback';

Это ошибка, что ph не предоставляет метод обратного вызова?


person Erik    schedule 14.06.2013    source источник


Ответы (4)


В вашем скрипте две проблемы:

  • ph — это не классический фантомный объект, а прокси-объект. node-phantom использовать веб-сокеты для вызова фантомов. Конечно, при такой реализации теряются некоторые функции.
  • функции не сериализуются при вызове page.set

Для печати пользовательского верхнего/нижнего колонтитула также требуется вызвать phantom.callback. Этот метод не задокументирован и поэтому не раскрывается node-phantom (и не может быть). Нам нужно найти способ применить этот метод в этом пакете.

Есть много решений. Вот мое возможное решение:

Сериализуйте свои функции в строку в вашем скрипте

var phantom = require('node-phantom');

phantom.create(function (err, ph) {
    ph.createPage(function (err, page) {
         page.set('paperSize', {
              format: 'A4',
              orientation: 'portrait',
              header: {
                            height: "1cm",
                            contents: 'function(pageNum, numPages) { return pageNum + "/" + numPages; }'
                        },
                        footer: {
                            height: "1cm",
                            contents: 'function(pageNum, numPages) { return pageNum + "/" + numPages; }'
                        }
         }, function () {   
             page.open('http://www.google.fr', function () {        
             page.render('google.pdf');
             ph.exit();
              })
         })
    })
});

отредактируйте bridge.js и добавьте phantom.callback + eval. Это позволит нам повторно подключить заголовок/нижний колонтитул .contents.

case 'pageSet':
            eval('request[4].header.contents = phantom.callback('+request[4].header.contents+')');
            eval('request[4].footer.contents = phantom.callback('+request[4].footer.contents+')');
            page[request[3]]=request[4];
            respond([id,cmdId,'pageSetDone']);
            break;

Как видите, это работает! (гугл на французском)

введите здесь описание изображения

person Cybermaxs    schedule 17.06.2013
comment
Спасибо. Это прекрасно работает. Я дам тебе награду, конечно. Могу я задать вам один вопрос. Что вы думаете об этом мосте (я имею в виду узел-фантом) для фантомов? Это хак или хорошее решение для работы с phantomjs в nodejs? - person Erik; 18.06.2013
comment
хорошо, хороший вопрос: должны ли мы использовать phantomjs с node.js? На stackoverflow.com/ есть хороший ответ. questions/15745394/ особенно Phantom и node имеют непримиримые различия. Лично я не большой фанат, но иногда нам приходится делать плохие вещи, чтобы просто выполнить работу. - person Cybermaxs; 18.06.2013
comment
@Cybermaxs, он отлично работает, как мы можем получить общее количество страниц? stackoverflow.com/questions/23516294/ - person Muhammad Rashid; 09.05.2014
comment
Если вас не устраивает node-phantom, вы также можете попробовать phridge (github.com/peerigon/phridge). Он обеспечивает более чистый и интуитивно понятный способ запуска скриптов внутри PhantomJS и возврата результатов обратно в node. - person Johannes Ewald; 26.05.2014
comment
Ага. Это только мое скромное мнение. Если не нравится, то вперед :) - person Johannes Ewald; 26.05.2014

К сожалению, node-phantom не поддерживает phantom.callback. Так как проект неактивен уже больше года, думаю вряд ли будет обновление в ближайшее время.

С другой стороны, phantomjs-node поддерживает phantom.callback() начиная с версии 0.6.6. Вы можете использовать его следующим образом:

var phantom = require('phantom');

phantom.create(function (ph) {
    ph.createPage(function (page) {
        page.open("http://www.google.com", function (status) {

            var paperConfig = {
                format: 'A4',
                orientation: 'portrait',
                border: '1cm',
                header: {
                    height: '1cm',
                    contents: ph.callback(function(pageNum, numPages) {
                        return '<h1>My Custom Header</h1>';
                    })
                },
                footer: {
                    height: '1cm',
                    contents: ph.callback(function(pageNum, numPages) {
                        return '<p>Page ' + pageNum + ' / ' + numPages + '</p>';
                    })
                }
            };

            page.set('paperSize', paperConfig, function() {
                // render to pdf
                page.render('path/to/file.pdf', function() {
                    page.close();
                    ph.exit();
                });
            });
        });
    });
});

Как вы также можете увидеть в этой сути.

person Ricardo Torres    schedule 19.11.2014
comment
Я больше не использую модуль node-phantom и нашел лучший github.com/peerigon/phridge - person Erik; 20.11.2014
comment
Эрик, большое спасибо. Phridge значительно проще остальных - person kibibu; 09.03.2016

node phantom, кажется, предоставляет этот прокси-объект через функцию создания (это должен быть ваш ph-объект):

var proxy={
                createPage:function(callback){
                    request(socket,[0,'createPage'],callbackOrDummy(callback));
                },
                injectJs:function(filename,callback){
                    request(socket,[0,'injectJs',filename],callbackOrDummy(callback));
                },
                addCookie: function(cookie, callback){
                    request(socket,[0,'addCookie', cookie],callbackOrDummy(callback));
                },
                exit:function(callback){
                    request(socket,[0,'exit'],callbackOrDummy(callback));
                },
                on: function(){
                    phantom.on.apply(phantom, arguments);
                },
                _phantom: phantom
            };

это означает, что вы, вероятно, можете получить доступ к обратному вызову фантомов следующим образом:

ph._phantom.callback
person hereandnow78    schedule 14.06.2013
comment
К сожалению, я получаю следующую ошибку: Обнаружено исключение: TypeError: Object #‹ChildProcess› не имеет метода «обратный вызов»; - person Erik; 14.06.2013
comment
чем извините, тогда я не вижу, как я могу вам помочь - person hereandnow78; 14.06.2013

Вот что я сделал для доступа к phantom.callback:

добавьте это в строку node-phantom.js 202:

callback: function(callback){
  request(socket,[0,'callback'],callbackOrDummy(callback));
},

незадолго до _phantom: phantom

и добавьте это в строку 45 bridge.js:

case 'callback':
    phantom.callback(request[3]);
break;

Надеюсь, поможет!

person rafaelcastrocouto    schedule 17.06.2013
comment
Это решение работает для вас? Я добавил код выше, и теперь я не получаю ошибку, но я также не получаю нижний колонтитул. Вы уверены, что этого достаточно? - person Erik; 17.06.2013
comment
Я только что показал вам, как получить доступ к объекту phantom.callback, а не ко всему решению ... ну, хороший вопрос: должны ли мы использовать phantomjs с node.js? классный вопрос #Cybermaxs - Betclic - person rafaelcastrocouto; 19.06.2013