2015-03-04 2 views
0

Итак, я разрабатываю сайт AngularJS, и мне поручено сделать его дружественным к обмену Facebook и SEO. Я выбрал PhantomJS в качестве возможного решения, чтобы оценить Javascript и выплюнуть выполненный html-код, который на данный момент только что заполняет метатеги facebook информацией.ngTransclude не работает на PhantomJS

Однако после получения phantomJS начала и оценки страницы, я получаю эту ошибку в моем хромом:

Error: [ngTransclude:orphan] Illegal use of ngTransclude directive in the template! No parent directive that requires a transclusion found. Element: <ul ng-transclude=""> http://errors.angularjs.org/1.2.22/ngTransclude/orphan?p0=%3Cul%20ng-transclude%3D%22%22%3E

После просмотра кода, я использую только transclude один раз на сайте, и что для генерации мое меню, состоящее из ul и transcluded li items.

app.directive('mvMenu', ['$rootScope', '$location', function ($rootScope, $location) { 
return { 
    restrict: 'E', 
    transclude: true, 
    controller: function ($scope, $element, $attrs) { 
     ... 
    }, 
    template: '<nav id="nav" role="navigation">' + 
       '<div class="block">' + 
       '<ul ng-transclude>' + 
       '</ul>' + 
       '</div>' + 
       '</nav>' 

} 
}]); 

Мои элементы Li также директива, и его код это:

app.directive('mvMenuItem', ['$location', function ($location) { 
return { 
    require: '^mvMenu', 
    restrict: 'E', 
    scope: { 
     text: '@text', 
     navLink: '@link', 
     icon: '@faicon' 
    }, 
    link: function (scope, element, attr, menuCtrl) { 
     ... 
    }, 
    template: '<li ng-class="{\'is-active\': isActive(navLink)}">' + 
    '<a ng-click="navAndToggleMenu(navLink)"><span class="fa {{icon}}"></span>{{text | translate}}</a>' + 
    '</li><!--' 
} 
}]); 

Я никогда не видел эту ошибку, когда сайт используется в любом браузере на любом устройстве. Он появляется только при оценке страницы с помощью phantomJS.

Это код phantomJS Я использую для создания HTML:

var page = require('webpage').create(); 
var system = require('system'); 

var lastReceived = new Date().getTime(); 
var requestCount = 0; 
var responseCount = 0; 
var requestIds = []; 
var startTime = new Date().getTime(); 

page.onResourceReceived = function (response) { 
if (requestIds.indexOf(response.id) !== -1) { 
    lastReceived = new Date().getTime(); 
    responseCount++; 
    requestIds[requestIds.indexOf(response.id)] = null; 
} 
}; 
page.onResourceRequested = function (request) { 
if (requestIds.indexOf(request.id) === -1) { 
    requestIds.push(request.id); 
    requestCount++; 
} 
}; 

function checkLoaded() { 
return page.evaluate(function() { 
    return document.all; 
}) != null; 
} 
// Open the page 
page.open(system.args[1], function() { }); 

var checkComplete = function() { 
// We don't allow it to take longer than 5 seconds but 
// don't return until all requests are finished 
if ((new Date().getTime() - lastReceived > 300 && requestCount ===    
responseCount) || new Date().getTime() - startTime > 10000 || checkLoaded()) { 
    clearInterval(checkCompleteInterval); 
    var result = page.content; 
    //result = result.substring(0, 10000); 
    console.log(result); 
    //console.log(results); 
    phantom.exit(); 
} 
} 
// Let us check to see if the page is finished rendering 
var checkCompleteInterval = setInterval(checkComplete, 300); 

Этот код взят из How to make a SPA SEO crawlable?, с той лишь разницей, что является неоспоримым «возвращение document.all» в методе оценки.

Заранее благодарен!

+0

Это работает, если вы удалите меню случайно? – AlexMA

+0

Где вы можете руководствоваться mvMenu? – HankScorpio

+0

@AlexMA Я попытался удалить меню, и да, оно выполнено без ошибок. Очевидно, что я хочу, чтобы меню было при использовании обычного браузера, так что, возможно, есть способ удалить меню только в phantomjs? – Marfyy

ответ

0

После запуска скрипта PhantomJS html, который вы выбрали, уже отображается. Не имеет смысла позволять угловой попытке отобразить его снова, когда вы открываете его в обычном браузере после его отображения.

Возьмем для примера следующую разметку:

<div ng-repeat="stuff in stuffList">{{stuff}}</div> 

Это получает, например, оказано

<div class="ng-repeat" ng-repeat="stuff in stuffList">Stuff1</div> 
<div class="ng-repeat" ng-repeat="stuff in stuffList">Stuff2</div> 

Что произойдет, если открыть уже обработанную разметку в браузере? ng-repeat будет выполнен снова, который приведет к следующей разметке:

<div class="ng-repeat" ng-repeat="stuff in stuffList">Stuff1</div> 
<div class="ng-repeat" ng-repeat="stuff in stuffList">Stuff1</div> 
<div class="ng-repeat" ng-repeat="stuff in stuffList">Stuff2</div> 
<div class="ng-repeat" ng-repeat="stuff in stuffList">Stuff2</div> 

Это не то, что вы хотите.

Перед сохранением разметки следует удалить все скрипты страниц. JavaScript больше не нужен.

page.evaluate(function(){ 
    [].forEach.call(document.querySelectorAll("script"), function(s){ 
     s.parentNode.removeChild(s) 
    }); 
}); 
fs.write("content.html", page.content); 
phantom.exit(); 
+0

Спасибо, что, кажется, исправили ошибку.У вас, похоже, есть опыт работы с phantomjs, может быть, вы можете помочь мне с новой проблемой, которую я заметил. Никакой код angularjs, похоже, не выполняется вообще после запуска кода выше. PhantomJS запускается через ASP.NET в моем MVC-контроллере за моим index.cshtml. Я использую код из [этой ссылки] (http://stackoverflow.com/questions/18530258/how-to-make-a-spa-seo-crawlable), который выполняет phantomjs.exe и скрипт. Есть ли какой-то шаг, который мне не хватает? – Marfyy

+0

Вы имеете в виду после применения моего исправления? Это идея. JavaScript не будет выполнен. Похоже, вы используете его для SEO, когда появляются боты, которые не знают JS. Возможно, я неправильно понял вашу проблему. –

Смежные вопросы