Javascript 异步调用后的DOM更新
我正在从服务器获取一些数据,并通过双向绑定更新DOM。然而,它并没有像预期的那样工作,我需要将它封装在一个丑陋的Javascript 异步调用后的DOM更新,javascript,html,angularjs,dom,Javascript,Html,Angularjs,Dom,我正在从服务器获取一些数据,并通过双向绑定更新DOM。然而,它并没有像预期的那样工作,我需要将它封装在一个丑陋的setTimeout函数中,以便DOM有时间进行更新 $http.post('myBackend.php', someData) .then(function(res){ $scope.data = res.data; doStuffWithDOMElements(); // Does not work }); 虽然这样做有效: $http.post('myBack
setTimeout
函数中,以便DOM有时间进行更新
$http.post('myBackend.php', someData)
.then(function(res){
$scope.data = res.data;
doStuffWithDOMElements(); // Does not work
});
虽然这样做有效:
$http.post('myBackend.php', someData)
.then(function(res){
$scope.someDataToPopulateDOMwith = res.data;
setTimeout(function(){ doStuffWithDOMElements();}, 50); // Yup, works
});
在没有超时的情况下给出错误的行“不能读取null的属性”如下所示:
let y_0 = document.getElementById("l_0").offsetTop;
在我的index.html中
<div id="l_{{$index}}" ng-repeat = "x in data"></div>
这很奇怪。难道不是应该自动更新每个包含在角度“事件”中的DOM元素吗<代码>$scope.$apply()不起作用,也不需要。这里怎么了?在angular中进行DOM操作时,这是众所周知的 请看这个在angularjs中每隔一段时间就会需要一次。最有可能的是初始化一个
jQuery插件
您的错误行:
let y_0 = document.getElementById("l_0").offsetTop;
这是因为您的DOM尚未设置,并且您正在尝试在DOM中获取尚未设置或渲染的元素
当您使用$timeout
时,它应该在通过Angular操作DOM之后以及在浏览器渲染之后运行(在某些情况下可能会导致闪烁)。这就是为什么在您设置$timeout
时它会在您的情况下工作
如果你想了解更多关于消化循环的知识。你也应该知道
- 如果使用指令中的$evalAsync对代码进行排队,则它应该在Angular操作DOM之后,但在浏览器呈现之前运行
- 如果代码是使用控制器中的$evalAsync排队的,那么它应该在Angular操作DOM之前(以及在浏览器呈现之前)运行—您很少希望这样做
- 如果使用$timeout对代码进行排队,则应在Angular操作DOM后以及浏览器渲染后运行(在某些情况下可能会导致闪烁)李>
setTimeout()
的效果。这就像C中的线程/进程产出。虽然它似乎说“立即运行”,但实际上它让浏览器有机会完成一些非JavaScript的事情,这些事情在处理新的JavaScript之前一直在等待完成
(实际上,setTimeout()
将新JavaScript重新排列在执行队列的末尾。请参阅注释以获得指向更详细解释的链接。)
IE6恰好更容易出现这种错误,但我已经在旧版本的Mozilla和Firefox上看到过这种情况
此外,关于为什么使用$timeout会时不时地派上用场,已经有很多文章和解释
链接,您可以在其中找到好的解释:
$http.post('myBackend.php', someData)
.then (function onFulfilled (response) {
$scope.someDataToPopulateDOMwith = response.data;
return response;
}).then (function onFulfilled2 (response) {
doStuffWithDOMElements();
});
这允许$q
服务在调用第二个实现处理程序之前执行摘要循环。AngularJS框架需要执行一个摘要循环,以便ng repeat
指令的监视处理程序有机会更新DOM。ng repeat
指令需要在dostuffWithDomeElements
函数能够安全地操作DOM之前完成DOM的更新
使用
$timeout
服务
避免使用原始浏览器setTimeout
功能,而是使用$timeout
服务。然后AngularJS$q
服务会自动进行周期消化
由于$timeout
服务返回承诺,因此它可以用于链接
$http.post('myBackend.php', someData)
.then (function onFulfilled (response) {
$scope.someDataToPopulateDOMwith = response.data;
return response;
}).then (function onFulfilled2 (response) {
//return $timeout promise
return $timeout(function(){return response}, 1000);
}).then (function onFulfilled3 (response) {
doStuffWithDOMElements();
});
因为调用允诺的then
方法会返回一个新的派生允诺,所以很容易创建一个允诺链。可以创建任意长度的链,并且由于一个承诺可以用另一个承诺解决(这将进一步推迟其解决),因此可以在链中的任何点暂停/推迟承诺的解决。这使得实现强大的API成为可能
重新考虑设计因素 AngularJS是一个MVW*框架 避免以编程方式操作HTMLDOM:操作HTMLDOM是AJAX应用程序的基石,但它既麻烦又容易出错。通过声明性地描述UI应该如何随着应用程序状态的变化而变化,您可以从低级DOM操作任务中解脱出来。大多数使用Angular编写的应用程序都不必以编程方式操纵DOM,尽管如果愿意,您可以这样做 研究如何建模
dostuffWithDoElements()
函数,并创建自定义指令来监视该模型和更新DOM。这更适合AngularJS框架,并将避免这些时间问题