我正在使用PhantomJS生成我的Angular应用程序的快照,如here所述。
为此,我有一个PhantomJS脚本,它读取URL,将HTML随地吐痰到控制台,以及一个读取我的sitemap.xml的节点脚本,并为每个URL运行PhantomJS脚本。
在我的应用程序中,我还有一个标志,当应用程序认为所有内容都已渲染时,它会被触发。我对这个标志的设置方式非常保守,只是为了确保在PhantomJS抓取HTML之前所有内容都得到了渲染。
我遇到的问题是这个。应用程序的菜单是使用ng-repeat和无序列表创建的。对于这个指令 - 只有这个指令 - 会发生的事情是列表元素重复至少两次(实际上比这更多)。
假设菜单看起来像这样,有三个项目:
<ul>
<li ng-repeat='item in items'>{{item.text}}</li>
我的快照脚本使用PhantomJS生成如下HTML:
<ul>
<li ng-repeat='item in items'>{{item.text}}</li>
<li ng-repeat='item in items'>{{item.text}}</li>
<li ng-repeat='item in items'>{{item.text}}</li>
如果我在浏览器中加载它,Angular会尽职尽责地执行ng-repeat指令 ,留下9个菜单项(每个3个)。
这显然不是我想要的,但我也不确定为什么会发生这种情况。而且我不知道问题是关于Angular中的某些内容还是PhantomJS中的内容。另外,为了让事情更令人沮丧,页面上还有其他ng-repeat指令执行得很好。
另一件事。菜单块在ng-if内。我不确定这是否重要,但也许确实如此。
那是怎么回事?以前有人遇到过这个问题吗?
编辑:
这里是设置标志的代码。由于我使用ui路由器,我等待$ viewContentLoaded事件。加载视图时会触发此事件。当事件被触发时,我设置或重置一个超时,它将改变$ rootScope上的标志。因为我有嵌套视图,所以每个页面加载会多次触发事件。想法是从上次发生此事件开始等待15秒,然后设置标志。
var timeout = null;
$scope.$on("$viewContentLoaded", function(){
var interval = 15000; //15 seconds
$rootScope.domStatus = 'notReady';
function setDomStatus(){
$rootScope.domStatus = 'ready';
}
if(timeout){
$timeout.cancel(timeout);
}
timeout = $timeout(setDomStatus, interval);
});
最后一个想法:
现在我开始怀疑这是否真的很重要。快照意味着由搜索引擎加载,搜索引擎不会执行JavaScript(事实上,这就是为什么快照是在一开始就制作的。)为了更好的衡量,我可以告诉Express寻找搜索在这种情况下引擎和NOT加载脚本。
答案 0 :(得分:2)
我想知道同样的问题。但行为是正确的。原因如下:
PhantomJS呈现您的AngularJS网页。
你面临的'问题'是在输出html中你仍然有你的javascript代码和角度指令。如果您在浏览器中查看输出,则会再次执行整个AngularJS / javascript代码。
所以有这个简单的角度模块:
var app = angular.module('webApp', []);
app.controller('myCtrl', function($scope){
$scope.values = ['AAA', 'BBB', 'CCC'];
});
以及这个html正文:
<body ng-app="webApp">
<div ng-controller="myCtrl">
<div ng-repeat="val in values">
{{val}}
</div>
</div>
</body>
PhantomJS提供的输出html如下所示:
<body ng-app="webApp" class="ng-scope">
<div ng-controller="myCtrl" class="ng-scope">
<!-- ngRepeat: val in values --><div ng-repeat="val in values" class="ng-binding ng-scope">
AAA
</div><!-- end ngRepeat: val in values --><div ng-repeat="val in values" class="ng-binding ng-scope">
BBB
</div><!-- end ngRepeat: val in values --><div ng-repeat="val in values" class="ng-binding ng-scope">
CCC
</div><!-- end ngRepeat: val in values -->
</div>
</body>
现在此输出应用于禁用javascript的浏览器和搜索引擎机器人。由于他们不再执行javascript,他们得到了所需的输出
AAA BBB CCC
如果您在启用javascript的浏览器中查看此html,则会再次执行所有'ng-repeat'指令,从而产生结果
AAA AAA AAA BBB BBB BBB CCC CCC CCC
要查看PhantomJS渲染html的方式,你必须关闭浏览器中的javascript功能。 (例如在Firefox中:在您的网址栏中输入'about:config'并将'javascript.enabled'更改为false)
答案 1 :(得分:0)
看起来PhantomJS正在捕捉页面,而角度正在忙着运行这个特定的ng-repeat(ng-if可能确实是原因)。如果在捕获页面之前添加延迟,则应该更好。如果确实如此,你要么保留延迟,要么修好你提到的旗帜。
有关如何设置标志的更多详细信息,我们可能会找到解决方案。