11

我正在尝试使用 Angular JS 指令将 div 的内容居中。

这是模板的简化版本:

<div id="mosaic" class="span12 clearfix" s-center-content>
    <div ng-repeat="item in hits" id="{{item._id}}" >
    </div>
</div>

这是指令:

 module.directive('sCenterContent', function() {
    var refresh = function(element){
        var aWidth= element.innerWidth();
        var cWidth= element.children()[0].offsetWidth;
        var cHeight= element.children()[0].offsetHeight;
        var perRow= Math.floor(aWidth/cWidth);
        var margin=(aWidth-perRow*cWidth)/2;
        if(perRow==0){
            perRow=1;
        }
        var top=0;
        element.children().each(function(index, child){
            $(child).css('margin-left','0px');
            if((index % perRow)==0){
                $(child).css('margin-left',margin+'px');
            }
        });
    };
    return {
        link : function(scope, element, attrs) {
            $(window).resize(function(event){
                refresh(element);
            });
        }
    };
});

它基本上浮动一些内部 div 并为每行的第一个 div 添加边距,因此内容居中。

当浏览器调整大小时,这可以正常工作。当我在初始化后尝试进行刷新时,问题就来了。

我已尝试使用此问题中所见的帖子链接功能。pre link 和 post link 函数按预期顺序调用,但不是在具有 s-center-content 指令的 elemenet 的子级渲染之后。由于未找到子项,刷新调用失败。

如何调用刷新以确保子项已得到处理?

4

4 回答 4

7

我认为使用 angular 的$watch是一个更好、更优雅的解决方案:

link : function(scope, element, attrs) {
            $(window).resize(function(event){
                refresh(element);
            });

            var watchCount = 0,
            unWatcher = $watch(
                function() {
                   return $('*[s-center-content] img').length !== 0;
                },
                function() {
                   // ensure refresh isn't called the first time (before the count of elements is > 0)
                   if (++watchCount === 1) {
                       return;
                   }

                   refresh(element);                   

                   // stop watching the element now that refresh has been called
                   unWatcher();
                }, true);
        }

关于停止观看:AngularJS:清除 $watch

于 2013-07-21T20:55:06.777 回答
5

这是一个反复出现的问题(在某个地方存在与此相关的问题,以及谷歌论坛中的一个线程..)

Angular 无法知道 dom 何时完成,它只能知道它调用的函数何时返回(以及任何 promise 都已解决)。如果这些函数是异步的并且没有回调或承诺,则无法获得通知。

我看到它完成的方式(以及我完成它的方式)是使用 setInterval 定期检查 DOM 以查看它是否处于完成状态。我讨厌这个解决方案,并且会很感激有一个替代方案,但是,它确实完成了工作。

于 2013-04-10T19:20:20.163 回答
1

终于成功了!

我使用了 livequery 插件,并在链接方法的末尾添加了以下行:

$('*[s-center-content] > *').livequery( function(event){
    refresh(element);
});

我使用指令选择元素的任何第一级子级(当前和未来),s-center-content并附加一个在元素添加到 DOM 时调用的处理程序。

编辑

最后一点。我的内容布局主要取决于具有动态评估src属性的内部图像。所以为了让它工作,我不得不把代码改成这样:

$('*[s-center-content] img').livequery( function(event){
    $(this).load(function(){
       refresh(element);                    
    });
});

将左浮动 div 居中放置的指令的完整代码如下。请注意,它依赖于将计算的边距添加到行中的第一个 div。

module.directive('sCenterContent', function() {
    var refresh = function(element){
        var aWidth= element.innerWidth();
        var cWidth= element.children()[0].offsetWidth;
        var cHeight= element.children()[0].offsetHeight;
        var perRow= Math.floor(aWidth/cWidth);
        var margin=(aWidth-perRow*cWidth)/2;
        if(perRow==0){
            perRow=1;
        }
        var top=0;
        element.children().each(function(index, child){
            $(child).css('margin-left','0px');
            if((index % perRow)==0){
                $(child).css('margin-left',margin+'px');
            }
        });
    };
    return {
        link : function(scope, element, attrs) {
            $(window).resize(function(event){
                refresh(element);
            });
            $('*[s-center-content] img').livequery( function(event){
                $(this).load(function(){
                    refresh(element);                   
                });
            });
        }
    };
});
于 2013-04-11T10:54:20.113 回答
0

我相信这可以用css来完成。无论数字如何,目标都是以目标为中心的元素吗?

[]  []  []  []  []

    []  []  []

如果是这样,这绝对可以通过 css 实现,并且可以用更少的复杂性来实现。这是一个例子:

http://codepen.io/thetallweeks/pen/kvAJb

于 2014-01-29T18:09:29.817 回答