简体   繁体   English

绑定数据后,从指令操作DOM

[英]Manipulate DOM from directive after data is bound

My goal is to create a directive that arranges a set of varied height divs into a pattern that eliminates whitespace between them. 我的目标是创建一个指令,将一组不同的高度div排列成一个模式,消除它们之间的空白。 Like how Pinterest tessellates divs into a mosaic: 就像Pinterest将divs镶嵌成马赛克一样:

Pinterest截图

My approach to this was: 我的方法是:

  1. Create a directive that will wrap a set of divs to tessellate. 创建一个指令,将一组div包装到tessellate。

     <tessellate columns="6"> <div ng-repeat="item in items" class="thumbnail"> {{item.name}} </div> </tessellate> 
  2. Use a directive template to set up the columns first. 使用指令模板首先设置列。 (tessellateTemplate.html) (tessellateTemplate.html)

     <div class="container"> <div class="row"> <div class="col-sm-{{12/columns}}" ng-repeat="i in numberToArray(columns) track by $index"></div> </div> </div> 
  3. Use the directive to grab the divs after the data has been bound to them and, one-by-one, add them to the column with the shortest height. 使用该指令在数据绑定到 div 抓取div 并逐个将它们添加到具有最短高度的列中。

     app.directive('tessellate', function () { return { restrict: 'E', scope: { columns: '=' }, controller: ['$scope', function ($scope) { // Ensure number of columns is divisible by 12. if (isNaN($scope.columns) || 12 % $scope.columns != 0) { $scope.columns = 6; } $scope.numberToArray = function (num) { return new Array(num); }; }], // Get child divs and add to template here. // Should I use compile or link?? templateUrl: "/app/directives/templates/tessellateTemplate.html" }; }); 

Seems simple enough, right? 看起来很简单吧? The problem I keep running into is that I can't figure out how to get the divs after data has been bound to them. 我一直遇到的问题是我无法弄清楚如何在绑定数据获取div。 This is important because the real height of the divs is needed to decide which column it should go in. 这很重要,因为需要div的实际高度来决定它应该进入哪一列。

Is there a way to manipulate the DOM in the directive after data is bound? 数据绑定后,有没有办法在指令中操作DOM?

To answer my own question, the only way I could figure this out was to use $timeout. 要回答我自己的问题,我能解决这个问题的唯一方法是使用$ timeout。 I'm not a fan of it, but it works. 我不是它的粉丝,但它有效。 If anyone has a better way, please post an answer. 如果有人有更好的方法,请发一个答案。 :) :)

I modified my directive template (tessellateTemplate.html) to transclude the divs: 我修改了我的指令模板(tessellateTemplate.html)来转换div:

<div>
    <div class="container">
        <div class="row">
            <div class="col-sm-{{12/columns}}" ng-repeat="i in numberToArray(columns) track by $index"></div>
        </div>
    </div>
    <div ng-transclude></div>
</div>

Then I modified my directive to have transclude: true and also do the tessellating in a $timeout (please don't laugh at my chained method calls, it's been a while since I've had to use JQuery :P): 然后我修改了我的指令以转换transclude: true并且还在$ timeout中进行细分(请不要嘲笑我的链式方法调用,已经有一段时间了,因为我必须使用JQuery:P):

app.directive('tessellate', function () {
    return {
        restrict: 'E',
        replace: true,
        transclude: true,
        scope: {
            columns: '='
        },
        controller: ['$scope', '$element', '$attrs', function ($scope, $element, $attrs) {
            // Ensure number of columns is divisible by 12.
            if (isNaN($scope.columns) || 12 % $scope.columns != 0) {
                $scope.columns = 6;
            }

            $scope.numberToArray = function (num) {
                return new Array(num);
            };

            $scope.getShortestColumn = function () {
                var cols = $element.children().first().children().first().children();
                var shortCol = null;
                angular.forEach(cols, function (col) {
                    col = angular.element(col);
                    if (shortCol == null || col.height() < shortCol.height()) {
                        shortCol = col;
                    }
                });
                return shortCol;
            };

            $timeout(function () {
                var divs = $element.children().first().next().children();
                for (var i = 0; i < divs.length; i++) {
                    $scope.getShortestColumn().append(divs[i]);
                }
            }, 0);
        }],
        templateUrl: "/app/directives/templates/tessellateTemplate.html"
    };
});

Usage remains the same: 用法保持不变:

<tessellate columns="6">
    <div ng-repeat="item in items">
        {{item.name}}
    </div>
</tessellate>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM