ngTransclude 在 PhantomJS 上失败
ngTransclude fails on PhantomJS
所以我正在开发一个 AngularJS 网站,我的任务是让它对 facebook 分享和 SEO 友好。我选择 PhantomJS 作为可能的解决方案,以评估 Javascript 并吐出执行的 html 代码,目前只是用信息填充 facebook 元标记。
但是在启动 phantomJS 并评估页面后,我在 chrome 中收到此错误:
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 项目组成。
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 items也是一个指令,它的代码是这样的:
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 评估页面时出现。
这是我用来生成 html:
的 phantomJS 代码
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?,唯一不同的是评估方法中的"return document.all"。
提前致谢!
在你 运行 你的 PhantomJS 脚本之后,你得到的 html 已经呈现。当您在普通浏览器中打开它已经呈现后,让 angular 尝试再次呈现它是没有意义的。
以下面的标记为例:
<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();
所以我正在开发一个 AngularJS 网站,我的任务是让它对 facebook 分享和 SEO 友好。我选择 PhantomJS 作为可能的解决方案,以评估 Javascript 并吐出执行的 html 代码,目前只是用信息填充 facebook 元标记。
但是在启动 phantomJS 并评估页面后,我在 chrome 中收到此错误:
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 项目组成。
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 items也是一个指令,它的代码是这样的:
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 评估页面时出现。
这是我用来生成 html:
的 phantomJS 代码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?,唯一不同的是评估方法中的"return document.all"。
提前致谢!
在你 运行 你的 PhantomJS 脚本之后,你得到的 html 已经呈现。当您在普通浏览器中打开它已经呈现后,让 angular 尝试再次呈现它是没有意义的。
以下面的标记为例:
<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();