132

アプリケーションが使用するさまざまなビューに個別のスタイルシートを使用する適切な/受け入れられる方法は何ですか?

現在、ビュー/パーシャルの html の一番上にリンク要素を配置していますが、最新のブラウザーはすべてサポートしているにもかかわらず、これは悪い習慣であると言われていますが、なぜそれが嫌われているのかがわかります。

もう 1 つの可能性は、個別のスタイルシートを index.html に配置することheadですが、パフォーマンスのためにビューがロードされている場合にのみスタイルシートをロードしたいと考えています。

css がサーバーから読み込まれるまでスタイリングが有効にならず、遅いブラウザーでフォーマットされていないコンテンツがすばやく表示されるため、これは悪い習慣ですか? ローカルでテストしていますが、まだこれを目撃していません。

Angular に渡されたオブジェクトを介して CSS をロードする方法はあります$routeProvider.whenか?

前もって感謝します!

4

7 に答える 7

150

この質問が古いことはわかっていますが、この問題に対するさまざまな解決策について多くの調査を行った後、より良い解決策を思いついたのではないかと思います。

更新 1:この回答を投稿してから、このコードをすべて、GitHub に投稿した単純なサービスに追加しました。リポジトリはここにあります。詳細については、お気軽にチェックしてください。

更新 2:この回答は、ルートのスタイルシートを取り込むための軽量ソリューションが必要な場合に最適です。アプリケーション全体でオンデマンド スタイルシートを管理するためのより完全なソリューションが必要な場合は、Door3 の AngularCSS プロジェクトをチェックアウトすることをお勧めします。よりきめ細かい機能を提供します。

将来誰かが興味を持った場合に備えて、私が思いついたのは次のとおりです。

<head>1.要素のカスタム ディレクティブを作成します。

app.directive('head', ['$rootScope','$compile',
    function($rootScope, $compile){
        return {
            restrict: 'E',
            link: function(scope, elem){
                var html = '<link rel="stylesheet" ng-repeat="(routeCtrl, cssUrl) in routeStyles" ng-href="{{cssUrl}}" />';
                elem.append($compile(html)(scope));
                scope.routeStyles = {};
                $rootScope.$on('$routeChangeStart', function (e, next, current) {
                    if(current && current.$$route && current.$$route.css){
                        if(!angular.isArray(current.$$route.css)){
                            current.$$route.css = [current.$$route.css];
                        }
                        angular.forEach(current.$$route.css, function(sheet){
                            delete scope.routeStyles[sheet];
                        });
                    }
                    if(next && next.$$route && next.$$route.css){
                        if(!angular.isArray(next.$$route.css)){
                            next.$$route.css = [next.$$route.css];
                        }
                        angular.forEach(next.$$route.css, function(sheet){
                            scope.routeStyles[sheet] = sheet;
                        });
                    }
                });
            }
        };
    }
]);

このディレクティブは次のことを行います。

  1. およびを使用して、オブジェクト内のすべてのアイテムのタグ$compileのセットを作成する html 文字列を( を使用して) コンパイルします。<link />scope.routeStylesng-repeatng-href
  2. コンパイルされた<link />要素のセットを<head>タグに追加します。
  3. 次に、 を使用してイベント$rootScopeをリッスンし'$routeChangeStart'ます。イベントごと'$routeChangeStart'に、「現在の」$$routeオブジェクト (ユーザーが去ろうとしているルート) を取得し、その部分固有の css ファイルを<head>タグから削除します。また、「次の」$$routeオブジェクト (ユーザーが行こうとしているルート) を取得し、その部分固有の css ファイルを<head>タグに追加します。
  4. また、ng-repeatコンパイルされた<link />タグの部分は、オブジェクトに追加またはオブジェクトから削除される内容に基づいて、ページ固有のスタイルシートのすべての追加および削除を処理しscope.routeStylesます。

注: これには、ng-app属性が<html>要素上にある必要があり、上<body>またはその内部にはありません<html>

2. を使用して、どのスタイルシートがどのルートに属しているかを指定します$routeProvider

app.config(['$routeProvider', function($routeProvider){
    $routeProvider
        .when('/some/route/1', {
            templateUrl: 'partials/partial1.html', 
            controller: 'Partial1Ctrl',
            css: 'css/partial1.css'
        })
        .when('/some/route/2', {
            templateUrl: 'partials/partial2.html',
            controller: 'Partial2Ctrl'
        })
        .when('/some/route/3', {
            templateUrl: 'partials/partial3.html',
            controller: 'Partial3Ctrl',
            css: ['css/partial3_1.css','css/partial3_2.css']
        })
}]);

cssこの構成は、各ページのルートを設定するために使用されるオブジェクトにカスタム プロパティを追加します。'$routeChangeStart'そのオブジェクトは、各イベントに として渡され.$$routeます。したがって、'$routeChangeStart'イベントをリッスンするときに、指定したプロパティを取得し、必要に応じてそれらのタグをcss追加/削除できます。この例では省略されているため、ルートで<link />のプロパティの指定は完全にオプションであることに注意してください。ルートにプロパティがない場合、ディレクティブはそのルートに対して何もしません。上記の例のように、ルートごとに複数のページ固有のスタイルシートを持つこともできることに注意してください。プロパティは、そのルートに必要なスタイルシートへの相対パスの配列です。css'/some/route/2'css<head>'/some/route/3'css

3. 完了です これら 2 つのことで、必要なすべてがセットアップされ、私の考えでは、可能な限りクリーンなコードでそれが実行されます。

私と同じようにこの問題に苦しんでいる可能性のある他の誰かを助けることを願っています.

于 2013-12-05T15:54:06.117 に答える
13

内のヘッドに新しいスタイルシートを追加できます$routeProvider。簡単にするために文字列を使用していますが、新しいリンク要素を作成したり、スタイルシートのサービスを作成したりすることもできます

/* check if already exists first - note ID used on link element*/
/* could also track within scope object*/
if( !angular.element('link#myViewName').length){
    angular.element('head').append('<link id="myViewName" href="myViewName.css" rel="stylesheet">');
}

ページでのプレロードの最大の利点は、背景画像がすでに存在していることです。FOUC

于 2013-03-04T02:38:11.773 に答える
5

@ sz3、今日は面白いことに、あなたが達成しようとしていたことを正確に実行する必要がありまし。そこで、上記のソリューションを使用しました。

しかし、私はあなたの最後の質問に答えるためにここにいます。何かアイデアはありますか?

コードをresolveに正しく含めていましたが、形式を少し変更する必要があります。

以下のコードを見てください。

.when('/home', {
  title:'Home - ' + siteName,
  bodyClass: 'home',
  templateUrl: function(params) {
    return 'views/home.html';
  },
  controler: 'homeCtrl',
  resolve: {
    style : function(){
      /* check if already exists first - note ID used on link element*/
      /* could also track within scope object*/
      if( !angular.element('link#mobile').length){
        angular.element('head').append('<link id="home" href="home.css" rel="stylesheet">');
      }
    }
  }
})

テストしたところ、正常に動作しています。html が挿入され、「/home」ルートに到達した場合にのみ「home.css」が読み込まれます。

完全な説明はここにありますが、基本的には解決します:形式でオブジェクトを取得する必要があります

{
  'key' : string or function()
} 

「キー」には好きな名前を付けることができます-私の場合は「スタイル」と呼びました。

値については、次の 2 つのオプションがあります。

  • stringの場合は、サービスのエイリアスです。

  • functionの場合は注入され、戻り値は依存関係として扱われます。

ここでの主なポイントは、コントローラーがインスタンス化されて $routeChangeSuccess イベントが発生する前に、関数内のコードが実行されることです。

それが役立つことを願っています。

于 2013-08-29T12:34:21.723 に答える