1

从我问过的上一个问题(http://stackoverflow.com/q/13383552/740318)我从创建一个设计不佳的过滤器到一个(仍然很糟糕但有效的)指令,这样做,我意识到它应该在正确实施时作为过滤器完成。现在奇怪的部分是(以我有限的理解)我将不得不重新建立一些最初实现的“hackish”技术,以使过滤器在转换时工作。

该指令是这样的:

widget.directive('truncate', function() {
  return {
    restrict: 'A',
    replace: true,
    // {{child.display}} will be a truncated copy of child.name
    template: '<a class="entity-name" href="{{child.url}}" title="{{child.name}}">{{child.display}}</a>',
    link: function(scope, element, attr) {
      var widthThreshold = $(element).parent().parent().width() * 0.85,
          // get the font-size without the 'px' at the end, what with media queries effecting font
          fontSize = $(element).css('font-size').substring(0, $(element).css('font-size').lastIndexOf('px')),
          sizeRatio = 29760/20621,
          characterCount = Math.floor((widthThreshold / fontSize) * sizeRatio);

      scope.$watch('child', function(val) {
        // Truncate it and trim any possible trailing white-space 
        var truncatedName = $.trim(scope.child.name.substring(0, characterCount));
        // Make sure characterCount isn't > the current length when accounting for the ...
        if (characterCount < scope.child.name.length + 3) {
          scope.child.display = truncatedName + '...';
        }
      });
    }
  }
});

为简单起见,我使用 jQuery 来获取.width()元素父级的父级。这给了我必须使用的总屏幕宽度。根据上述值(以及诸如 font-size CSS 属性之类的东西),我截断字符串以尽可能合理地显示,然后以三个句点(“...”)结束。这很简单,因为元素被传递给指令,我可以简单地使用$(element)jQuery 来获取标识符并解决它。

现在使用过滤器,我仅限于传入的字符串,并且没有像使用指令那样的元素。以我有限的知识,在过滤器中完成此操作的唯一方法是$('a:contains("' + name + '")')使用之前实现的原始(并且可能是过程密集型)方法(在上面提到的上一个问题中),或者可以动态地为每个方法分配一个 id<a>并传递它进入过滤器。也许类似于(未经测试的伪代码,希望它能够理解这一点):

<script>
function entityController($scope, $http) {
  $http.get('/path/to/json').success(function(res) {
    /* Sample return JSON ("uuid" is a unique database stored identifier):
     * {
     *   children: [
     *     { uuid:"123", url:"path/to/file", name:"File Name", display:"File Name" },
     *     { uuid:"234", url:"path/to/file2", name:"Second File Name", display:"Second File Name" },
     *     ...
     *   ]
     * }
     */
    $scope.children = res.children
  });
}
</script>
<body class="ng-controller:entityController" ng-controller="entityController">
  <div ng-repeat="child in children">
    <!-- Not sure if {{child.name | truncate:uuid}} would work, hopefully it conveys the point -->
    <a id="{{child.uuid}}" href="{{child.url}}" title="{{child.name | truncate:uuid}}">{{child.display}}</a>
  </div>
</body>

现在,如果我想通过 jQuery 访问它,我将不得不通过一些 hackish 来复制上述指令的功能,例如:

var app = angular.module('app', []);

app.filter('truncate', function() {
  return function(str, uuid) {
    var widthThreshold = $('#' + uuid).parent().parent().width() * 0.85,
        fontSize = $('#' + uuid).css('font-size').substring(0, $('#' + uuid).lastIndexOf('px')),
        ...
});

它似乎从那里螺旋式下降,在那里我继续查询 DOM 以获取越来越多的信息,这些信息让我思考指令是否是不正确的(但“更干净”,如果它曾经是这样的话)方法。使用过滤器时,是否有适当的方法来访问 DOM 属性,例如父元素的宽度或字体大小,而不必滥用 jQuery,并增加我的语法只是为了访问过滤器中的 DOM ?

4

1 回答 1

3

AFAIK,没有办法通过角度将 $element 传递给过滤器。指令是用于 DOM 操作的。虽然您可能觉得您只是在尝试缩短范围内的字符串,但您实际上是在尝试操纵添加到 DOM 中的内容,因此该指令是正确的选择,IMO。

也就是说,您是否查看过 CSS text-overflow?它可能会在没有 JavaScript 的情况下完成您想要做的事情。

于 2012-11-19T14:07:37.940 回答