1

$scopeIE8 で奇妙な問題が発生しました。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;
    }
  });

次に、このフィルターを with で使用しますng-repeat

<a class="entity-name" href="{{child.url}}" title="{{child.name}}" ng-cloak>{{child.name|truncate}}</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. に置き換えwindowWidthwidthThresholdjQuery を.parent()2 回チェーンして値を識別します (基本的に、ウィンドウではなく親 (x2) 要素の幅を取得する場合は、より正確な値になります)。
  2. childと呼ばれる追加のキーを追加しましたdisplay。これは、child.namejQuery.text()を使用して切り捨てられchild.nameた .
  3. truncPntになりますcharacterCount(変数を省略しないように覚えようとしています)

問題は、(プロンプトが表示された場合) javascript を強制終了するまで、jQuery がブラウザーをフリーズさせることです。Firefox はそれを表示するかもしれませんし、Chrome はまだハングしていません。私はまだ IE でテストしていませんが、前者より悪いと思います。

問題のメイン要素の上にある 2 つの親の値を適切に取得しchild.display、親の div を超えてラップ/拡張しないように切り捨てるにはどうすればよいですか?

更新 2:


親 div の幅、フォント サイズ、および神のみぞ知る比率を考慮して、主に DOM ベースの計算の考えを捨てることにしました。フォントサイズに関係なく、一貫して同様の結果が得られるものを得るまで、私は真剣に数式に取り組みました. メディア クエリは問題の文字列のフォント サイズ 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 + '...';
        }
      });
    }
  }
});

興味深いことに、DOM の変更とスコープ内のプロパティの変更に関する Brandon Tilley のコメントに完全に戻ったと思います。プロパティを変更するように変更したので、おそらくフィルターでより適切に機能するでしょうか? この種の操作をフィルターとディレクティブで処理する必要があるかどうかを決定する一般的な要因は何ですか?

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 に答える