1

我对 IE8 有一个奇怪的问题,如果我尝试$scope通过 AngularJS 的双向数据绑定在模板中呈现变量,它不会替换{{child.name}}为正确的值。这肯定与以下过滤器的低效率有关:

  filter('truncate', function() {
    return function(name) {
      // It's just easier to use jQuery here
      var windowWidth = $(window).width(),
          nameElement = $('a:contains("' + name + '")'),
          truncPnt = Math.floor(name.length * 0.9);

      while (nameElement.width() > windowWidth * 0.75 && truncPnt > 6) {

        truncPnt = Math.floor(truncPnt * 0.9);
        name = name.substring(0, truncPnt);
        nameElement.text(name + ' ...');
      }
      return name;
    }
  });

然后,我将此过滤器与 withng-repeat一起使用:

<a class="entity-name" href="{{child.url}}" title="{{child.name}}" ng-cloak>{{child.name|truncate}}</a>

总体目标是根据屏幕宽度将传递到过滤器的变量截断,用“...”替换任何截断的字符。我相当有信心这个过滤器是原因,因为我有一个类似的函数在处理程序的 a 上被调用.resize()$(window)如果我使用 IE8 并调整浏览器窗口的大小,它会导致{{child.name}}渲染为正确的值,但是仅当我调整浏览器大小时。

更新:


所以我已经摆脱了上面的过滤器,并用一个非常相似的指令代替了它。这是我第一次尝试创建自定义指令,所以我相当肯定它可以做得更好,减去我目前似乎无法解决的明显缺陷。该指令如下:

.directive('truncate', function() {

  return {
    restrict: 'A',
    replace: true,
    template: '<a class="entity-name" href="{{child.url}}" title="{{child.name}}">{{child.display}}</a>',
    link: function(scope, element, attr) {
      var widthThreshold = $(element[0]).parent().parent().width() * 0.85;

      scope.$watch('child', function(val) {
        var elementWidth = $(element[0]).width(),
            characterCount = scope.child.name.length;

        while ($(element[0]).width() > widthThreshold || characterCount > 5) {
          characterCount--;
          scope.child.display = scope.child.name.substring(0, characterCount) + ' ...';
        }
      });
    }
  }
});

我将部分替换为简单的:

<a truncate="child"></a>

这与过滤器的区别如下(减去明显的过滤器与指令):

  1. 替换windowWidthwidthThreshold, 通过链接 jQuery.parent()两次来识别值(本质上,当获取父 (x2) 元素而不是窗口的宽度时,它是一个更准确的值)。
  2. child为被调用添加了一个附加键display。这将child.name是用于显示的截断版本,而不是使用 jQuery.text()并仅使用截断的child.name.
  3. truncPnt变成characterCount(尽量记住不要缩写变量)

现在的问题是 jQuery 冻结了浏览器,直到我终止了 javascript(如果出现提示)。Firefox 可能会显示它,Chrome 还没有挂起,虽然我还没有在 IE 中进行测试,但我想比前者更糟。

可以做些什么来正确获取相关主元素上方的两个父元素的值,并截断child.display以使其不会包裹/延伸到父 div 之外?

更新 2:


我决定放弃主要基于 DOM 的计算的想法,转而使用数学,考虑父 div 的宽度、字体大小和天知道的比例。我认真地插入了一个公式,直到我得到了无论字体大小都始终给出相似结果的东西。媒体查询确实会影响相关字符串的字体大小 CSS,因此我需要考虑这一点,否则不同字体大小的截断字符串的长度会有一些巨大差异:

.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')),
          // ... Don't ask...
          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 = scope.child.name.substring(0, characterCount).replace(/^\s\s*/, '').replace(/\s\s*$/, '');
        // Make sure characterCount isn't > the current length when accounting for the '...'
        if (characterCount < scope.child.name.length + 3) {
          scope.child.display = truncatedName + '...';
        }
      });
    }
  }
});

有趣的是,我相信我又回到了 Brandon Tilley 关于修改 DOM 与修改范围内的属性的评论。现在我已将其更改为修改属性,它可能会更好地用于过滤器?对于这种操作是否应该在过滤器和指令中处理,通常决定因素是什么?

4

1 回答 1

1

我参考文档:

指令

指令是一种教授 HTML 新技巧的方法。在 DOM 编译期间,指令与 HTML 匹配并执行。这允许指令注册行为,或转换 DOM。

http://docs.angularjs.org/guide/directive

过滤器

Angular 过滤器格式化数据以显示给用户。除了格式化数据,过滤器还可以修改 DOM。这允许过滤器处理诸如有条件地将 CSS 样式应用于过滤后的输出等任务。

http://docs.angularjs.org/guide/dev_guide.templates.filters

我只会将过滤器用于更改数据格式的目的,仅此而已。老实说,我相信为您的目的使用过滤器是合适的。正如文档所说,过滤器可以修改 DOM 我看不出你应该使用指令的原因,过滤器似乎就是你要找的东西。(除了一个错误可能会迫使你使用指令)

于 2012-11-15T20:32:36.743 回答