【问题标题】:Angular Digest Loop on ng-style / Dynamic Photo Gridng-style / Dynamic Photo Grid 上的 Angular Digest 循环
【发布时间】:2017-07-25 04:59:57
【问题描述】:

我有一个改变过滤对象的过滤器。但是当我使用ng-style="item.gridSize" 我的过滤器:(大小网格的算法取自(根据我的需要更改)来自Here

angular.module("custom.modules.photoGrid", []).filter('photoSearch', [function () {
    function getGrid(photos){
        var output = [];
        var HEIGHTS = [];
        var COLUMN_WIDTH = 227;
        var MARGIN = 6;
        var DELTA = 20;

        var size = window.innerWidth - 50;
        var n_columns = Math.floor(size / (2 * (COLUMN_WIDTH + MARGIN)));
        create_columns(n_columns);
        var small_images = [];

        function create_columns(n) {
            HEIGHTS = [];
            for (var i = 0; i < n; ++i) {
                HEIGHTS.push(0);
            }
        }

        function get_min_column() {
            var min_height = Infinity;
            var min_i = -1;
            for (var i = 0; i < HEIGHTS.length; ++i) {
                if (HEIGHTS[i] < min_height) {
                min_height = HEIGHTS[i];
                min_i = i;
                }
            }
            return min_i;
        }

        function gridSize(i, is_big) {
            var size = {
                'margin-left': (MARGIN + (COLUMN_WIDTH + MARGIN) * i)+'px',
                'margin-top': (HEIGHTS[Math.floor(i / 2)] * (COLUMN_WIDTH + MARGIN))+'px',
                'width': is_big ? (COLUMN_WIDTH * 2 + MARGIN)+'px' : COLUMN_WIDTH+'px',
                'height': is_big ? (COLUMN_WIDTH * 2 + MARGIN)+'px' : COLUMN_WIDTH+'px'
            };
            return size;
        }
        function createGrid(data){
            if (data.length >= 2) {
                for(var i = 0; i < data.length; i++){
                    var column = get_min_column();
                    if (Math.random() > 0.8) {
                        data[i]['gridSize'] = gridSize(column * 2, true);
                        HEIGHTS[column] += 2;
                    } else {
                        small_images.push(i);
                        if (small_images.length === 2) {
                            data[small_images[0]]['gridSize'] = gridSize(column * 2, false);
                            data[small_images[1]]['gridSize'] = gridSize(column * 2 + 1, false);
                            HEIGHTS[column] += 1;
                            small_images = [];
                        }
                    }
                }
                if (small_images.length) {
                    column = get_min_column();
                    data[(data.length-1)]['gridSize'] = gridSize(column * 2, false);
                }
            }

            return data;
        }
        var grid = createGrid(photos);
        return grid;
    }


    return function(photos, search) {
        var filtered = [];
        if(!!search){ /**@case1 if only search query is present**/
            search = search.toLowerCase();
            for(var i = 0; i < photos.length; i++){
                if(photos[i].photo_name.toLowerCase().indexOf(search) !== -1){
                    filtered.push(photos[i]);
                }
            }

        }else {
            /**@case2 no query is present**/
            filtered = photos;
        }
        filtered = getGrid(filtered);
        return filtered;
    }
}]);

HTML:

<input type="text" ng-model="input.value"> <span>{{ results.length }}</span> Photo Found
<div ng-repeat='photo in photos | photoSearch:input.value as results track by photo.id' class="photo-item" ng-style="photo.gridSize">
                    <img ng-src="/photos/{{photo.url}}">
                </div>

一个小解释: 每次ng-model input.value 更改过滤器都会运行并为过滤后的照片数组创建不同的网格。所有维度都写在gridSize 中,这会导致摘要循环。

到目前为止我已经尝试过:我已将 ng-repeat 移至指令中,但这样我无法访问 result.lengthinput.value

我也尝试过 bindonce 指令,但像 bo-style="photo.gridSize" 一样使用它不会在用户搜索后更改网格(并且在逻辑上是正确的,因为只出价一次,但值发生了变化。

所以我的问题是如何让ng-repeat 分配新的grdiSize 属性而不在摘要循环中运行。

更新: JSFiddle

工作小提琴: JSFiddle

【问题讨论】:

  • 嗯,你能创建一个 pnkr 或 fiddle 来让你的问题重现吗?
  • @lin 更新添加了 JSFiddle(你可以在控制台中看到)错误信息
  • 我认为您使用 ng-style 的方式不正确。它应该类似于:ng-style="{'margin-left' : calculationLogic, 'margin-top': calculationLogic}"

标签: javascript css angularjs angularjs-directive angularjs-scope


【解决方案1】:

有几个问题。这不完全是 ng-style 问题,而是在每个摘要周期中,您的照片都在计算不同的样式对象,从而导致另一个摘要周期运行。

我发现的一些问题:

  • 逻辑错误是给出 0 列,因此在计算 margin-top 时导致大小给出 NaN 并失败。为了解决这个问题,我从 1 列中添加了一个默认值。
  • 您的Math.random() &gt; 0.8 在每次执行您的过滤器函数时给出不同的结果。在每个摘要循环中,由于Math.random() 给出不同的结果,因此它强制执行另一个摘要循环(您正在更新 gridSize 对象 - 因为ng-repeat 中的每个元素都有一个$watch 它检测到更改并强制执行一个摘要循环) , 等等。那是控制台中的错误日志。

我创建了这个有效的fiddle。主要变化是

在声明数组后,为每张照片定义一个固定的随机值

$scope.photos.forEach(function(onePhoto){
    onePhoto.randomValue = Math.random();
  });

然后在过滤器中检查这个值

if (data[i].randomValue > 0.8) {
}

并在创建列时设置至少 1 列

var n_columns = Math.max(1, Math.floor(size / (2 * (COLUMN_WIDTH + MARGIN))));

另外(但我相信这仅发生在您的小提琴中),没有要过滤的photo_name,所以我改用id

您可能想用其他默认值修复NaN 问题,但至少现在您知道控制台错误的问题。

如果您想在每次执行搜索时更新您的 randomValue,您可以在您的 input.value 上放置一个 $watch,将迭代照片和创建随机值的代码移动到一个函数中,并在回调中使用它那个手表功能。因此,每次更新搜索结果时,您的网格都会使用不同的随机值,而不会干扰摘要循环。 类似this

var updateRandomValues = function() {
    $scope.photos.forEach(function(onePhoto){
        onePhoto.randomValue = Math.random();
      });
  };
  updateRandomValues();
  $scope.$watch('input.value', function(newVal, oldVal) {
    if (newVal !== oldVal) {
        updateRandomValues();
    }
  });

但是,如果您只想在获得不同结果时获得不同的 css 样式(请记住,如果您键入并获得与以前相同的结果,无论如何它都会更新您的网格布局),您应该$watch 是结果变量。赞this

$scope.$watch('results', function(newVal, oldVal) {
    if (newVal !== oldVal) {
        updateRandomValues();
    }
  });

【讨论】:

  • 您好,感谢您指出一些问题,这里是更新的小提琴jsfiddle.net/3uxntktd/15 我已将所有内容移至指令并创建了 PositionService。似乎工作。顺便说一句,有时在调整大小时,会有 1 个额外的列无法填充大图像,但可以插入小图像,您能就此提出建议吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-08-15
  • 1970-01-01
  • 1970-01-01
  • 2020-01-25
  • 1970-01-01
相关资源
最近更新 更多