这是我的标记:
<div resizer>
<div class="a"></div>
<div class="b">
This content generated dynamically using ng-include and other directives inside
</div>
</div>
第二个div(.b
)改变它的高度(动态添加在其中的元素)。我写了一个指令,应该根据可用的高度更新第一个div(.a
):
'use strict';
myModule.directive('resizer', ['$timeout', function ($timeout) {
return {
restrict: 'A',
link: function (scope, element, attrs) {
function updateSizes(event) {
var a = element.find('.a');
var b = element.find('.b');
var bHeight = b.outerHeight();
var totalHeight = element.height();
a.height(totalHeight - bHeight);
}
element.on('some-event', updateSizes);
$timeout(updateSizes);
}
};
}]);
当我启动我的应用程序时,有时候,我的div的高度等于零(高度:0),因为b.outerHeight();和element.height();返回零 这是为什么?我使用了$ timeout,因此浏览器有时间呈现视图 有什么想法吗?
答案 0 :(得分:2)
您有两种可能的选择(请参阅ngInclude docs here):
我建议使用第二个选项,因为每次要使用指令时都会保存以指定onload事件。
您可以在链接函数中指定侦听器,如下所示:
function link(scope, element, attrs) {
scope.$on('$includeContentLoaded', function(){
console.log('Template included');
// you can add all your height calculation and DOM manipulation here
});
}
看一下this demo Plunker(我希望内容完全不言自明) 您的代码应该看起来像这样:
'use strict';
myModule.directive('resizer', ['$timeout', function ($timeout) {
return {
restrict: 'A',
link: function (scope, element, attrs) {
function updateSizes(event) {
var a = element.find('.a');
var b = element.find('.b');
var bHeight = b.outerHeight();
var totalHeight = element.height();
a.height(totalHeight - bHeight);
}
scope.$on('$includeContentLoaded', updateSizes);
}
};
}]);
答案 1 :(得分:1)
您的问题似乎是在您的指令模板中有ng-include
。
ng-include
本身就是一个指令,它创造了一个新的范围。然而,只要呈现HTML,就会执行resizer
指令link
函数,因此ng-include
- d模板已经存在,但其内容尚未加载(甚至是单独的如果之前未加载模板,则 HTTP / GET 请求。
我确信还有更多修复方法,但可以使用onload
标记的ng-include
参数:
// ... your directive ...
link: function (scope, element, attrs) {
function updateSizes(event) {
console.log (element.find('.b').outerHeight());
}
scope.ngOnload = updateSizes;
}
现在进入你的html模板:
<div resizer>
<div class="a"></div>
<div class="b">
<div ng-include="'sometemplate.html'" onload="ngOnload()"></div>
</div>
</div>
这对我起了作用,并且div.b
元素outerHeight在控制台日志中不再为0。
我知道,您已经使用$timeout
来等待浏览器了。如果我的解决方案不适合您,那些div
中必须加载一些奇怪的东西,可能需要解决方案所需的更多细节。但是debugger
函数中带有chrome调试器的updateSizes
语句可以提供很多帮助。
答案 2 :(得分:1)
使用angular的常见模式是使嵌套指令 require 一个父指令并将其自身注册到父指令。您可以使用此模式来解决您的问题。我已将嵌套指令 resizer-source 和 resizer-dest 添加到您的标记中:
<div resizer>
<div class="a" resizer-dest></div>
<div class="b" resizer-source>
This content generated dynamically using ng-include and other directives inside
</div>
</div>
myModule.directive('resizerSource', function () {
return {
require: '^resizer',
link: function (scope, element, attrs, ctrl) {
ctrl.registerSource(element);
}
};
});
myModule.directive('resizerDest', function () {
return {
require: '^resizer',
link: function (scope, element, attrs, ctrl) {
ctrl.registerDest(element);
}
};
});
myModule.directive('resizer', ['$timeout', function ($timeout) {
return {
controller: function($scope) {
var a,b;
function update() {
if (a && b) {
var bHeight = b.outerHeight();
var totalHeight = element.height();
a.height(totalHeight - bHeight);
}
}
this.registerSource = function(elm) {
b = elm;
update();
}
this.registerDest = function(elm) {
a = elm;
update();
}
}
};
}]);
如果出于某种原因, b 的高度即使在 b 的链接功能运行时也不可用,您可以通过设置 b 的高度为$watch
,仅当手表评估为正数时才会注册 b 。之后,取消观察者,除非您期望元素的高度继续变化。
如果我要观察b的大小,我将不得不引起一个摘要周期(通过调用$ apply()或$ digest)。我通知调整器使用dom事件进行更新。你觉得怎么样?
(1)$watch
尺寸是一项昂贵的操作,因为每次检查高度时它都会强制重绕。所以尽快取消$watch
。 (2)无法保证角度会在正确的时间触发消化周期,因此可能需要使用您提到的dom事件。
出于这些原因,使用$watch
可能不是最好的方法,但这实际上取决于您的具体情况。
在链接函数中使用元素不是一个好习惯吗?
使用控制器而不是链接功能没有任何意义。他们有不同的调用顺序,但这不会在这里发挥作用。
您无法访问控制器中的“元素”..是否将链接函数中的缩放器代码安全?我的意思是,我必须将registerSource和registerDest放在控制器上
如果需要,您可以将$element
注入控制器。或者,您可以将指令自己的控制器添加到require
属性,以便从link
函数访问它。您是否选择将代码放入控制器或link
函数通常会归结为组织,因此如果它简化了代码,请不要害怕使用控制器而不是link
函数。
答案 3 :(得分:1)
我怀疑这个问题可能是因加载ng-include资源的延迟造成的。您可以预加载缓存:
$templateCache.put('template.html', '<b>Template</b>');
或者如果内容来自$ http电话:
$http.get('template.html', {cache:$templateCache});
答案 4 :(得分:1)
我知道这不是您正在寻找的答案,但为什么您要走这么简单的事情呢?
The best programming is, no programming
我建议您只为此目的使用css
<style>
.tbl {display:table}
.tbl-row {display:table-row}
.tbl-cell {display:table-cell}
</style>
<div class="tbl">
<div class="tbl-row">
<div class="tbl-cell">Foo</div>
<div class="tbl-cell">
This content generated dynamically using ng-include and other directives inside
</div>
</div>
</div>