1

更新Plunker 到项目: http ://plnkr.co/edit/oKB96szQhqwpKQbOGUDw?p=preview

我有一个使用 AngularJS Bootstrap 网格的 AngularJS 项目。我需要所有网格元素具有相同的大小,以便它们正确堆叠。我创建了一个 angularJs 指令,该指令在放置在所述网格元素中时自动调整网格元素的大小。我有 2 条指令为我执行此操作 指令 1:onload 指令 2:imageonload

指令 2 有效。如果网格元素使用图像,则在图像加载后,指令会触发一个事件,将网格元素高度发送到所有其他网格元素。如果通过事件发出的高度大于正在侦听事件的网格元素的高度,则侦听网格元素将其高度更改为更大的高度。这样最大的高度就变成了所有网格元素的高度。

指令 1 不起作用。这个放置在最外层的网格元素 html 元素上,并在元素加载时触发。问题是当元素加载并且调用 onload 指令时,AngularJS 还没有填写所述网格元素中的数据。结果是AngularJS数据绑定后的真实高度没有作为事件广播。

我想到的唯一解决方案(但没有尝试过)是将图像 url 添加到存在但没有任何数据的图像中,并将其放置在网格元素中(没有放置空白之前的任何图像)。然后我可以调用 imageonload 而不是 onload ,我很确定 angularjs 数据绑定到那时就会发生。

问题是这很hacky。我宁愿能够在网格元素中没有图像,并且能够调用我的自定义 onload 指令并让 onload 指令在 angularJS 数据绑定到网格元素中的所有数据绑定变量之后计算高度。

这是我的 imageonload 指令

.directive('imageonload', function($rootScope) {
    return {
    restrict: 'A',
    link: function(scope, element, attrs) {
        scope.heightArray = [];
        scope.largestHeight = 50;
        element.bind('load', function() {
            broadcastThumbnailHeight();
        });

        scope.$on('imageOnLoadEvent', function(caller, value){
            var el = angular.element(element);
            var id = el.prop('id');
            var pageName = el.prop('title');
            if(pageName == value[0]){
                if(scope.largestHeight < value[1]){
                   scope.largestHeight = value[1];
                    var nestedString = el.prop('alt');
                    if(nestedString == "")
                        nestedString = "1";
                    var nested = parseInt(nestedString);
                    nested = nested - 1;
                    var inte = 0;
                    var thumbnail = el["0"];
                    var finalThumbnailContainer = thumbnail.parentElement;
                    while(inte != nested){
                        finalThumbnailContainer = finalThumbnailContainer.parentElement;
                        inte++;
                    }
                    var innerEl = angular.element(finalThumbnailContainer);
                    var height = value[1];
                    innerEl.height(height);
                }
            }
        });
        scope.$on('findHeightAndBroadcast', function(){
            broadcastThumbnailHeight();


        });
        scope.$on('resetThumbnailHeight', function(){
            scope.largestHeight = 50;


        });
        function broadcastThumbnailHeight(){
            var el = angular.element(element);
            var id = el.prop('id');
            var alt = el.prop('alt');
            if(alt == "")
                alt = "1";
            var nested = parseInt(alt);
            nested = nested - 1;
            var pageName = el.prop('title');
            var inte = 1;
            var thumbnail = el["0"];
            var finalThumbnail = thumbnail.parentElement;
            while(inte != nested){
                finalThumbnail = finalThumbnail.parentElement;
                inte++;
            }
            var elZero = el["0"];
            var clientHeight = finalThumbnail.clientHeight;
            var arr = [];
            arr[0] = pageName;
            arr[1] = clientHeight;
            $rootScope.$broadcast('imageOnLoadEvent', arr);
        }
    }
};

})

这是我的 onload 指令

.directive('onload', function($rootScope) {
return {
    restrict: 'A',
    link: function(scope, element, attrs) {
        scope.largestHeight=100;
        getHeightAndBroadcast();
        scope.$on('onLoadEvent', function(caller, value){
            var el = angular.element(element);
            var id = el.prop('id');
            var pageName = el.prop('title');
            if(pageName == value[0]){
                if(scope.largestHeight < value[1]){
                    scope.largestHeight = value[1];
                    var height = value[1];
                    el.height(height);
                }
            }
        });
        function getHeightAndBroadcast(){
            var el = angular.element(element);
            var h = el["0"].children;
            var thumbnailHeightElement = angular.element(h);
            var pageName = el.prop("title");
            var clientHeight = thumbnailHeightElement["0"].clientHeight;
            var arr = [];
            arr[0] = pageName;
            arr[1] = clientHeight;
            if(clientHeight != undefined)
                $rootScope.$broadcast('onLoadEvent', arr);
        }
    }
};

})

这是我使用 imageonload 的网格元素之一的示例。请注意图像 html 元素中的 imageonload 指令。这行得通。在网格元素的最外层 html 上还有一个 onload 指令。那是行不通的。我在 Firebug 中仔细检查了这一点,发现 onload 正在计算 AngularJS 数据绑定完成之前的高度。

<div class="thumbnail col-md-3" id="{{product.id}}" title="thumbnailAdminProductsGrid" onload>
<div class="row">
    <div class="containerz">
        <div class="row-fluid">
            <div class="col-md-2"></div>
            <div class="col-md-7">
                <div class="textcenterinline">
                    <!--tag--><img class="img-responsive"  id="{{product.id}}" title="imageAdminProductsGrid" alt=6 ng-src="{{product.baseImage}}" imageonload/><!--end tag-->
                </div>
            </div>
        </div>
    <div class="caption">
        <div class="testing">
            <div class="row-fluid">
                <div class="col-md-12">
                    <h3 class="">
                        <!--tag--><a href="javascript:void(0);" ng-click="loadProductView('{{product.id}}')">{{product.name}}</a><!--end tag-->
                    </h3>
                </div>
            </div>

            <div class="row-fluid">
                <div class="col-md-12">
                    <p class="lead"><!--tag--> {{product.price}}</p><!--end tag-->
                </div>
            </div>
            <div class="row-fluid">
                <div class="col-md-12">
                    <p><!--tag-->{{product.inStock}} units available<!--end tag--></p>
                </div>
            </div>
            <div class="row-fluid">
                <div class="col-md-12">
                    <p class=""><!--tag-->{{product.generalDescription}}<!--end tag--></p>
                </div>
            </div>
            <!--tag-->
            <div data-ng-if="product.specialized=='true'">
                <div class="row-fluid">
                    <div class="col-md-12" ng-repeat="varCat in product.varietyCategoriesAndOptions">
                        <b><h4>{{varCat.varietyCategoryName}}</h4></b>
                        <select ng-model="varCat.varietyCategoryOption" ng-options="value.varietyCategoryOptionId as value.varietyCategoryOptionValue for (key,value) in varCat.varietyCategoryOptions">
                        </select>
                    </div>
                </div>
            </div>
            <!--end tag-->
            <div class="row-fluid">
                <div class="col-md-12">
                    <!--tag--><div ng-if="product.weight==0"><b>Free Shipping</b></div><!--end tag-->
                </div>
            </div>


        </div>
    </div>
    </div>
</div>

这是我的一个网格元素之一的 html 示例,它只使用“onload”指令而不是“imageonload”

<div class="thumbnail col-md-3" title="thumbnailCouponGrid" onload>
<div class="innnerContainer">

    <div class="text-center">
        {{coupon.name}}
        <br />
        <br />
        <b>Description</b>
        <br />
        {{coupon.description}}
        <br />
        <br />
        <button class="btn btn-large btn-primary" ng-click="goToCoupon()">View Coupon Details</button>
    </div>

</div>

imageonload 函数可能看起来有点混乱,因为我使用 img html 属性“alt”向指令指示 imageonload 放置在网格元素的最外层 html 下方多少层。我们必须拥有它,这样指令才能知道要在哪个 html 元素上设置新高度。我还使用“title”属性来设置此网格调整大小适用于哪个网格(这样您可以在同一页面上多次使用该指令用于不同的网格,并且不会触发错误网格的事件)。

有谁知道我如何在 angularJS 绑定到网格元素后调用“onload”指令?

为了完整起见,这里有 2 个图像(几乎看起来只有 1 个),第二个是包含具有图像并使用“imageonload”指令的网格元素的网格,第一个是包含不使用图像的网格元素的网格和仅使用“onload”指令。

在此处输入图像描述 在此处输入图像描述

4

1 回答 1

1

getHeightAndBroadcast();将您的函数封装在$timeout调用中似乎可以完成这项工作。

请看这个 Plunker:http ://plnkr.co/edit/cncatsnFBrYm57tgPKHr?p=preview

它是您的一个分支,在您的 script.js 中添加了一个小部分,即:

注入 $timeout

link: function(scope, element, attrs, $timeout) {

在调用中封装getHeightAndBroadcast();函数$timeout

    // Use of $timeout with 0 delay fixes function applied before DOM update completion.
    $timeout(function() {
      getHeightAndBroadcast();  
    }, 0, true);

希望这就是它!您可以在没有可选延迟的情况下调用 $timeout 和 invokeApply 参数。

这是官方的 $timeout 文档:https ://docs.angularjs.org/api/ng/service/ $timeout

于 2014-05-27T15:21:45.353 回答