与AngularJS的砌体

Dan*_*nze 30 javascript jquery angularjs

我正在开发一个" 艺术画廊 "应用程序.

随意下载github上源代码并使用它.

具有完整来源的Plunker.

目前的工作是让Masonry与Angular合作:

.directive("masonry", function($parse) {
  return {
    restrict: 'AC',
    link: function (scope, elem, attrs) {
      elem.masonry({ itemSelector: '.masonry-brick'});
    }
  };     
})
.directive('masonryBrick', function ($compile) {
  return {
    restrict: 'AC',
    link: function (scope, elem, attrs) {
      scope.$watch('$index',function(v){
        elem.imagesLoaded(function () {
          elem.parents('.masonry').masonry('reload');
        });
      });
    }
  };    
});
Run Code Online (Sandbox Code Playgroud)

这不能很好地工作,因为:

  • 随着内容的增长,在整个容器上进行重载的开销也随之增加.

reload函数:

  • " 追加 "项目,而是重新安排容器中的每个项目.
  • 当从结果集中过滤掉项目时,是否可以触发重新加载.

在应用程序的上下文中,我给出了上面的链接,这个问题变得非常容易复制.

我正在寻找一个将使用指令来利用的解决方案:

.masonry('appended', elem).masonry('prepended', elem)

而不是.masonry('reload')每次都执行.

.masonry('reload') 当从结果集中删除元素时.


编辑

该项目已更新为使用下面的工作解决方案.

GitHub上获取源代码

查看Plunker上的工作版本

Jam*_*arp 19

我一直在玩这个,@ ganaraj的答案非常简洁.如果你坚持$element.masonry('resize');他的控制器的appendBrick方法和帐户加载图像,那么它看起来像是有效的.

这是一个带有它的plunker fork:http://plnkr.co/edit/8t41rRnLYfhOF9oAfSUA

这是必要的原因是因为只有在元素上初始化砌体或者调整容器大小时才计算列数,此时我们没有任何砖块,所以它默认为单个列.

如果你不想使用'resize'方法(我认为它没有记录),那么你可以调用$ element.masonry(),但这会导致重新布局,所以你只想在只调用它时调用它第一块砖被添加.

编辑:我已将上面的plunker更新为仅resize在列表长度超过0时调用,并且在同一$摘要周期中删除多个砖时仅执行一次"重新加载".

指令代码是:

angular.module('myApp.directives', [])
  .directive("masonry", function($parse, $timeout) {
    return {
      restrict: 'AC',
      link: function (scope, elem, attrs) {
        elem.masonry({ itemSelector: '.masonry-brick'});
        // Opitonal Params, delimited in class name like:
        // class="masonry:70;"
        //elem.masonry({ itemSelector: '.masonry-item', columnWidth: 140, gutterWidth: $parse(attrs.masonry)(scope) });
      },
      controller : function($scope,$element){
          var bricks = [];
          this.appendBrick = function(child, brickId, waitForImage){
            function addBrick() {
              $element.masonry('appended', child, true);

              // If we don't have any bricks then we're going to want to 
              // resize when we add one.
              if (bricks.length === 0) {
                // Timeout here to allow for a potential
                // masonary timeout when appending (when animating
                // from the bottom)
                $timeout(function(){
                  $element.masonry('resize');  
                }, 2);  
              }

              // Store the brick id
              var index = bricks.indexOf(brickId);
              if (index === -1) {
                bricks.push(brickId);
              }
            }

            if (waitForImage) {
              child.imagesLoaded(addBrick);      
            } else {
              addBrick();
            }
          };

          // Removed bricks - we only want to call masonry.reload() once
          // if a whole batch of bricks have been removed though so push this
          // async.
          var willReload = false;
          function hasRemovedBrick() {
            if (!willReload) {
              willReload = true;
              $scope.$evalAsync(function(){
                willReload = false;
                $element.masonry("reload");
              });
            }
          }

          this.removeBrick = function(brickId){
              hasRemovedBrick();
              var index = bricks.indexOf(brickId);
              if (index != -1) {
                bricks.splice(index,1);
              }
          };
      }
    };     
  })
  .directive('masonryBrick', function ($compile) {
    return {
      restrict: 'AC',
      require : '^masonry',
      link: function (scope, elem, attrs, MasonryCtrl) {

      elem.imagesLoaded(function () {
        MasonryCtrl.appendBrick(elem, scope.$id, true);
      });

      scope.$on("$destroy",function(){
          MasonryCtrl.removeBrick(scope.$id);
      }); 
    }
  };
});
Run Code Online (Sandbox Code Playgroud)


g00*_*0fy 7

这不是你想要的(prependappend),但应该是你正在寻找的:

http://plnkr.co/edit/dmuGHCNTCBBuYpjyKQ8E?p=preview

您的指令版本会触发reload每个版本brick.对于整个列表更改,此版本仅触发一次仅重新加载.

方法很简单:

  1. bricks在父母中注册新的masonry controller
  2. $watch注册bricks和火灾的变化masonry('reload')
  3. 删除元素时brickbricks注册表中删除 -$on('$destroy')
  4. 利润

您可以扩展此方法以执行您想要的操作(使用prependappend)但我没有看到您为什么要这样做的任何理由.这也会复杂得多,因为您必须手动跟踪元素的顺序.我也不相信它会更快 - 相反它可能会更慢,因为append/prepend如果你改变很多砖块你将不得不触发多次.

我不太确定,但我想你可以用ng-animate它(JavaScript动画版)

我们tiling在日历应用中为事件实现了类似的功能.这个解决方案最快.如果有人有更好的解决方案,我很乐意看到.

对于那些想要代码的人:

angular.module('myApp.directives', [])
  .directive("masonry", function($parse) {
    return {
      restrict: 'AC',
      controller:function($scope,$element){
        // register and unregister bricks
        var bricks = [];
        this.addBrick = function(brick){
          bricks.push(brick)
        }
        this.removeBrick = function(brick){
          var index = bricks.indexOf(brick);
          if(index!=-1)bricks.splice(index,1);
        }
        $scope.$watch(function(){
          return bricks
        },function(){
          // triggers only once per list change (not for each brick)
          console.log('reload');
          $element.masonry('reload');
        },true);
      },
      link: function (scope, elem, attrs) {
        elem.masonry({ itemSelector: '.masonry-brick'});
      }
    };     
  })
  .directive('masonryBrick', function ($compile) {
    return {
      restrict: 'AC',
      require:'^masonry',
      link: function (scope, elem, attrs,ctrl) {
        ctrl.addBrick(scope.$id);

        scope.$on('$destroy',function(){
          ctrl.removeBrick(scope.$id);
        });
      }
    };
  });
Run Code Online (Sandbox Code Playgroud)

编辑: 有一件事我忘了(加载图片) - 只需在加载所有图片时调用'reload'.我试着稍后编辑代码.


gan*_*raj 1

Angular 记录最少的功能之一是它的指令控制器(尽管它位于www.angularjs.org的首页上))。

这是一个利用此机制的修改版 plunker。

http://plnkr.co/edit/NmV3m6DZFSpIkQOAjRRE

人们确实使用指令控制器,但它已被用于(和滥用)其可能不适合的用途。

在上面的 plunker 中,我只修改了directives.js 文件。指令控制器是指令之间通信的机制。有时,在一个指令中完成所有操作是不够/容易的。在本例中,您已经创建了两个指令,但使它们交互的正确方法是通过指令控制器。

我无法弄清楚你什么时候想前置,什么时候想附加。我目前只实现了“append”。

另请注意:如果资源尚未实现承诺,您可以自己实现它们。做到这一点并不难。我注意到您正在使用回调机制(我不推荐)。你已经在那里做出了承诺,但你仍然在使用回调,我无法理解为什么。

这是否为您的问题提供了正确的解决方案?

有关文档,请参阅http://docs.angularjs.org/guide/directive > 指令定义对象 > 控制器。