dom完成渲染后如何运行指令?

Jan*_*nis 115 jquery dom callback document-ready angularjs

我有一个看似简单的问题,没有明显的(通过阅读Angular JS文档)解决方案.

我有一个Angular JS指令,它根据其他DOM元素的高度进行一些计算,以定义DOM中容器的高度.

类似于此的东西在指令内部发生:

return function(scope, element, attrs) {
    $('.main').height( $('.site-header').height() -  $('.site-footer').height() );
}
Run Code Online (Sandbox Code Playgroud)

问题是,当指令运行时,$('site-header')无法找到,返回一个空数组而不是我需要的jQuery包装DOM元素.

是否有我可以在我的指令中使用的回调只在DOM加载后运行,我可以通过正常的jQuery选择器样式查询访问其他DOM元素?

Art*_*eev 137

这取决于你的$('site-header')的构造方式.

您可以尝试使用$ timeout和0延迟.就像是:

return function(scope, element, attrs) {
    $timeout(function(){
        $('.main').height( $('.site-header').height() -  $('.site-footer').height() );
    });        
}
Run Code Online (Sandbox Code Playgroud)

解释它是如何工作的:,.

不要忘记注入$timeout你的指令:

.directive('sticky', function($timeout)
Run Code Online (Sandbox Code Playgroud)

  • 您的链接解释解释了为什么超时技巧在JavaScript中有效,但在AngularJS的上下文中却没有.来自[官方文档](http://docs.angularjs.org/guide/concepts#runtime):"_ [...] 4. $ evalAsync队列用于调度需要在当前堆栈之外发生的工作框架,但在浏览器的视图渲染之前.**这通常使用setTimeout(0)**完成,但是setTimeout(0)方法会慢,并且可能导致视图闪烁,因为浏览器在每个事件之后呈现视图. ..] _"(强调我的) (19认同)
  • 我遇到了类似的问题,并且发现在执行我的指令之前我需要大约300毫秒才能加载DOM.我真的不喜欢插入那些看似随意的数字.我确定DOM的加载速度会因用户而异.那么我怎么能确定300ms适用于使用我的应用程序的任何人? (12认同)
  • 谢谢,我试着让它工作多年,直到我意识到我没有将`$ timeout`传递给指令.卫生署.现在一切正常,欢呼. (5认同)
  • 是的,你需要将`$ timeout`传递给这样的指令:`.directive('sticky',function($ timeout){return function(scope,element,attrs,controller){$ timeout(function(){}) ;}); };` (5认同)
  • 对这个答案不太满意..虽然它似乎回答了OP的问题..它的情况非常具体,而且它与问题的更一般形式有关(即在dom加载后运行指令)并不明显+它只是太hacky ...没有任何关于角度的具体内容 (5认同)

rjm*_*226 44

我是这样做的:

app.directive('example', function() {

    return function(scope, element, attrs) {
        angular.element(document).ready(function() {
                //MANIPULATE THE DOM
        });
    };

});
Run Code Online (Sandbox Code Playgroud)

  • @timhc22 元素是对触发指令的 DOMElement 的引用,您的建议不会导致对页面 Document 对象的 DOMElement 引用。 (2认同)

jna*_*llo 37

可能作者不再需要我的答案了.尽管如此,为了完整起见,我觉得其他用户可能会发现它很有用.最好和最简单的解决方案是$(window).load()在返回函数的主体内部使用.(或者你可以使用document.ready.这取决于你是否需要所有图像).

$timeout在我的拙见中使用是一个非常弱的选择,在某些情况下可能会失败.

这是我使用的完整代码:

.directive('directiveExample', function(){
   return {
       restrict: 'A',
       link: function($scope, $elem, attrs){

           $(window).load(function() {
               //...JS here...
           });
       }
   }
});
Run Code Online (Sandbox Code Playgroud)

  • 你假设这里有jQuery. (6认同)
  • @JonathanCremin jQuery选择是根据OP的问题 (3认同)

sun*_*rls 8

有一个ngcontentloaded事件,我想你可以使用它

.directive('directiveExample', function(){
   return {
       restrict: 'A',
       link: function(scope, elem, attrs){

                $$window = $ $window


                init = function(){
                    contentHeight = elem.outerHeight()
                    //do the things
                }

                $$window.on('ngcontentloaded',init)

       }
   }
});
Run Code Online (Sandbox Code Playgroud)

  • 你能解释`$ $ window`在做什么吗? (20认同)
  • 看起来像一些咖啡脚本,也许是为了将$($ window)和$ window注入到指令中 (2认同)

JSV*_*JSV 5

如果由于外部资源而无法使用$ timeout,并且由于时间的特定问题而无法使用指令,请使用broadcast.

添加$scope.$broadcast("variable_name_here");所需的外部资源或长时间运行的控制器/指令完成后.

在加载外部资源后添加以下内容.

$scope.$on("variable_name_here", function(){ 
   // DOM manipulation here
   jQuery('selector').height(); 
}
Run Code Online (Sandbox Code Playgroud)

例如,在延迟HTTP请求的承诺中.

MyHttpService.then(function(data){
   $scope.MyHttpReturnedImage = data.image;
   $scope.$broadcast("imageLoaded");
});

$scope.$on("imageLoaded", function(){ 
   jQuery('img').height(80).width(80); 
}
Run Code Online (Sandbox Code Playgroud)

  • 这不会解决问题,因为加载的数据并不意味着它们已经在DOM中呈现,即使它们位于绑定到DOM元素的适当范围变量中.它们在作用域中加载的时刻与dom中的渲染输出之间存在一个时间跨度. (2认同)