AngularJS $timeout 没有等待 UI-Router 在计算值之前完成渲染
AngularJS $timeout isn't waiting for UI-Router to finish rendering before computing values
我通过 angularAMD
使用 angularJS
和 requirejs
将一个复杂的应用程序连接在一起。
我的一个状态有两个简单的视图,如下所示:
$stateProvider
.state("common", {
url: "/",
views: {
"view1": {
templateUrl: "view1.tpl.html"
},
"view2": {
templateUrl: "view2.tpl.html"
}
}
});
html
<div ui-view="view1"></div>
<div ui-view="view2"></div>
View1
有一个指令:
.directive('checkViewOneBoxWidth', function ($timeout) {
return {
restrict: 'A',
link: function (scope, elem, attrs) {
var linkFunctionAfterDomComplete = function () {
console.log(elem[0].scrollWidth);
}
$timeout(linkFunctionAfterDomComplete, 0);
}
}
})
和 view2
有一个样式表,可以对页面应用一些样式,包括更改 view1
容器的 height
和 width
。
我希望函数 linkFunctionAfterDomComplete
计算元素的 height
和 width
属性 after DOM 已被 view2
中的样式表修改,因此我将 linkFunctionAfterDomComplete
函数包装在 $timeout()
中。
这里 checkViewOneBoxWidth
中的 console.log
报告了这个元素的大小,在 view2
中样式表的样式修改了这个元素的大小之前,尽管我们在应用 view2
的样式并且 DOM 完成后,预计 $timeout
会导致 linkFunctionAfterDomComplete
函数计算此元素的大小。
我怎样才能 linkFunctionAfterDomComplete
计算反映元素在完全呈现并应用所有样式后的真实状态的元素属性?
你需要传递一个函数给$timeout
:
$timeout(function() {
console.log('timeout: view 1 linked')
}, 0);
或:
var fn = function () {
console.log('timeout: view 1 linked');
};
$timeout(fn, 0);
以下:
$timeout(console.log('timeout: view 1 linked'), 0);
将立即执行 console.log
,然后将 return 值 (undefined
) 作为第一个参数传递给 $timeout
。
演示: http://plnkr.co/edit/zWgoJihcMH693fWfUp09?p=preview
不确定您在实际应用程序中是否遇到同样的问题,但我认为我应该 post 无论如何。
基于编辑的新答案
问题是您的 link 元素位于视图模板中,而不是 index.html。
如果您将它移动到 index.html,它将按您预期的那样工作(并且在这种情况下您不需要 $timeout
,除非您的实际应用程序从中添加自定义 HTML指令):
演示: http://plnkr.co/edit/m3sriF2YYH5T8y42R5Lr?p=preview
如果你在视图模板中保留link并保持超时,基本上会发生这种情况:
- Angular 将 运行 它的编译函数准备所有绑定和视图。
- 视图中的 HTML 将被插入到 DOM 中,指令将执行并且
console.log
将被添加到超时队列中。
- link 元素现已插入 DOM,浏览器将开始检索 CSS。超时队列中的
console.log
将执行。
请注意,CSS 的提取是异步的,超时队列中的 console.log
将在 CSS 的提取和解析完成之前执行。
另请注意,您可能会在不同的浏览器中看到不同的行为。
有解决方案,但可能会变得非常混乱。
阅读更多相关信息:
When is a stylesheet really loaded?
我建议将 link 移动到 index.html。
我通过 angularAMD
使用 angularJS
和 requirejs
将一个复杂的应用程序连接在一起。
我的一个状态有两个简单的视图,如下所示:
$stateProvider
.state("common", {
url: "/",
views: {
"view1": {
templateUrl: "view1.tpl.html"
},
"view2": {
templateUrl: "view2.tpl.html"
}
}
});
html
<div ui-view="view1"></div>
<div ui-view="view2"></div>
View1
有一个指令:
.directive('checkViewOneBoxWidth', function ($timeout) {
return {
restrict: 'A',
link: function (scope, elem, attrs) {
var linkFunctionAfterDomComplete = function () {
console.log(elem[0].scrollWidth);
}
$timeout(linkFunctionAfterDomComplete, 0);
}
}
})
和 view2
有一个样式表,可以对页面应用一些样式,包括更改 view1
容器的 height
和 width
。
我希望函数 linkFunctionAfterDomComplete
计算元素的 height
和 width
属性 after DOM 已被 view2
中的样式表修改,因此我将 linkFunctionAfterDomComplete
函数包装在 $timeout()
中。
这里 checkViewOneBoxWidth
中的 console.log
报告了这个元素的大小,在 view2
中样式表的样式修改了这个元素的大小之前,尽管我们在应用 view2
的样式并且 DOM 完成后,预计 $timeout
会导致 linkFunctionAfterDomComplete
函数计算此元素的大小。
我怎样才能 linkFunctionAfterDomComplete
计算反映元素在完全呈现并应用所有样式后的真实状态的元素属性?
你需要传递一个函数给$timeout
:
$timeout(function() {
console.log('timeout: view 1 linked')
}, 0);
或:
var fn = function () {
console.log('timeout: view 1 linked');
};
$timeout(fn, 0);
以下:
$timeout(console.log('timeout: view 1 linked'), 0);
将立即执行 console.log
,然后将 return 值 (undefined
) 作为第一个参数传递给 $timeout
。
演示: http://plnkr.co/edit/zWgoJihcMH693fWfUp09?p=preview
不确定您在实际应用程序中是否遇到同样的问题,但我认为我应该 post 无论如何。
基于编辑的新答案
问题是您的 link 元素位于视图模板中,而不是 index.html。
如果您将它移动到 index.html,它将按您预期的那样工作(并且在这种情况下您不需要 $timeout
,除非您的实际应用程序从中添加自定义 HTML指令):
演示: http://plnkr.co/edit/m3sriF2YYH5T8y42R5Lr?p=preview
如果你在视图模板中保留link并保持超时,基本上会发生这种情况:
- Angular 将 运行 它的编译函数准备所有绑定和视图。
- 视图中的 HTML 将被插入到 DOM 中,指令将执行并且
console.log
将被添加到超时队列中。 - link 元素现已插入 DOM,浏览器将开始检索 CSS。超时队列中的
console.log
将执行。
请注意,CSS 的提取是异步的,超时队列中的 console.log
将在 CSS 的提取和解析完成之前执行。
另请注意,您可能会在不同的浏览器中看到不同的行为。
有解决方案,但可能会变得非常混乱。
阅读更多相关信息:
When is a stylesheet really loaded?
我建议将 link 移动到 index.html。