Javascript 延迟大小计算直到呈现ui

Javascript 延迟大小计算直到呈现ui,javascript,css,html,angularjs,angularjs-directive,Javascript,Css,Html,Angularjs,Angularjs Directive,这是我的标记: <div resizer> <div class="a"></div> <div class="b"> This content generated dynamically using ng-include and other directives inside </div> </div> 当我启动应用程序时,有时,我的div的高度等于零(高度:0),因为b.oute

这是我的标记:

<div resizer>
    <div class="a"></div>
    <div class="b">
        This content generated dynamically using ng-include and other directives inside
    </div>
</div>
当我启动应用程序时,有时,我的div的高度等于零(高度:0),因为b.outerHeight();和元素。高度();返回零。
为什么呢?我使用$timeout,以便浏览器有时间呈现视图。

有什么想法吗?

您的问题似乎是指令模板中有一个
ng include

ng include
本身就是一个指令,它创建了一个新的作用域。但是,您的
resizer
指令
link
函数会在呈现HTML时立即执行,因此
ng include
-d模板已经存在,但其内容尚未加载(如果之前未加载模板,则它甚至是一个单独的HTTP/GET请求)

我确信还有更多的修复,但其中之一是使用
ng include
标记的
onload
参数:

// ... 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
中肯定加载了一些奇怪的内容,可能需要解决方案的更多详细信息。但是,在
updateSizes
函数中使用chrome debugger的
debugger
语句可能会有很大帮助。

您有两种可能的选择(请参阅):

  • 使用ngInclude onload事件
  • 在加载内容时,侦听ngInclude发出的$includeContentLoaded事件
  • 我建议使用第二个选项,因为它将保存您在每次使用指令时指定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
        });
    }
    
    '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);
    
            }
        };
    }]);
    
    请看一看(我希望内容是不言自明的)。
    您的代码应该是这样的:

    function link(scope, element, attrs) {
        scope.$on('$includeContentLoaded', function(){
            console.log('Template included');
            // you can add all your height calculation and DOM manipulation here
        });
    }
    
    '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);
    
            }
        };
    }]);
    
    方法 使用angular的常见模式是,嵌套指令需要父指令,并向父指令注册自身。您可以使用此模式来解决您的问题。我已将嵌套指令resizer sourceresizer 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>
    
    调脂器 增塑剂 更灵活 如果由于某种原因,b的链接功能运行时,b的高度不可用,您可以通过在b的高度上设置
    $watch
    并仅在手表计算为正数时注册b,使其更加灵活。之后,取消观察者,除非您期望元素的高度继续改变

    附加信息 如果我要监视b的大小,我必须引起一个摘要循环(通过调用$apply()或$digest)。我正在通知resizer使用dom事件进行更新。你觉得怎么样

    (1)
    $watch
    调整尺寸是一项昂贵的操作,因为每次检查高度时都会强制回流。因此,请尽快取消
    $watch
    。(2) 不能保证angular会在正确的时间触发摘要循环,因此可能需要使用您提到的dom事件

    出于这些原因,使用
    $watch
    可能根本不是最好的方法,但这取决于您的具体情况

    在链接函数中使用元素不是一种好的做法吗

    使用控制器而不是链接函数没有任何不符合角度的地方。它们有不同的调用顺序,但在这里不起作用

    您无权访问控制器中的“元素”。。将大小调整器代码放入链接函数是否安全?我的意思是,我必须把registerSource和registerDest放在控制器上


    如果需要,可以将
    $element
    注入控制器。或者,您可以将指令自己的控制器添加到
    require
    属性,以从
    链接
    功能访问它。无论您选择将代码放入控制器还是
    链接
    功能,通常都取决于组织,因此,如果
    链接
    功能简化了代码,请不要害怕使用控制器。

    我怀疑问题可能是由于加载ng include资源的延迟造成的。您可以预加载缓存:

    $templateCache.put('template.html', '<b>Template</b>');
    

    我知道这不是你想要的答案,但为什么你要走这么远,让这些简单的事情都能实现呢

    最好的编程方式是不编程

    我只建议您使用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>
    
    
    .tbl{display:table}
    .tbl行{显示:表行}
    .tbl单元格{显示:表格单元格}
    福
    此内容是使用ng include和内部的其他指令动态生成的
    

    示例:

    角度方式是一个常见且好的问题。AngularJS有一个自然的流程,其中不断变化的模型重新定义了内容或样式。所以通常,对于改变内容之类的东西,“角度方式”就是HTML方式。似乎你想调整你的div大小以适应内容。但是,如果我理解正确的话,你做的工作太多了。div本质上就是要根据内容调整大小。因此,除非将固定高度或宽度指定给div,否则它的行为应该与您喜欢的一样。如果您想要额外的行为(填充、居中、固定宽度),这将更多地是CSS答案而不是“角度”。这应该由CSS来完成。@DaveA这不能使用CSS来完成,因为我还需要在运行时更新大小。我将更新我的代码-还有一个导致大小更新的事件绑定。现在清楚了吗?@Naor,还不清楚。我错过了一件大事。在我看来,div会自动调整大小以适应其内容。由于我对数据或内容进行了模型绑定,并对其进行了更改(或更改了指令以使用不同的模板),因此我的div已经调整了大小。我不知道,你的答案是什么意思
    $templateCache.put('template.html', '<b>Template</b>');
    
    $http.get('template.html', {cache:$templateCache});
    
    <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>