アプリケーションが使用するさまざまなビューに個別のスタイルシートを使用する適切な/受け入れられる方法は何ですか?
現在、view/partialのhtmlの上部にリンク要素を配置していますが、最新のブラウザーはすべてサポートしていますが、これは悪い習慣であると言われていますが、なぜそれが嫌われているのかがわかります。
別の可能性は、index.htmlのhead
に個別のスタイルシートを配置することですが、パフォーマンスの名前でビューがロードされている場合にのみスタイルシートをロードしたいです。
Cssがサーバーからロードされるまでスタイリングが有効にならず、遅いブラウザーで未フォーマットのコンテンツがすばやくフラッシュされるため、これは悪い習慣ですか?ローカルでテストしていますが、まだこれを目撃していません。
Angularの$routeProvider.when
に渡されたオブジェクトを介してCSSをロードする方法はありますか?
前もって感謝します!
私はこの質問が今では古いことを知っていますが、この問題のさまざまな解決策について多くの研究を行った後、私はより良い解決策を思いついたと思う。
UPDATE 1:この回答を投稿して以来、GitHubに投稿した単純なサービスにこのコードをすべて追加しました。リポジトリは here にあります。詳細については、お気軽にご確認ください。
UPDATE 2:必要なのは、ルートのスタイルシートを取り込むための軽量なソリューションだけである場合、この答えは素晴らしいです。アプリケーション全体でオンデマンドスタイルシートを管理するためのより完全なソリューションが必要な場合は、 Door3のAngularCSSプロジェクト をチェックアウトすることをお勧めします。より詳細な機能を提供します。
将来の誰かが興味を持っている場合、ここに私が思いついたものがあります:
1。 <head>
要素のカスタムディレクティブを作成します:
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;
});
}
});
}
};
}
]);
このディレクティブは次のことを行います。
$compile
および<link />
を使用して、scope.routeStyles
オブジェクト内のすべてのアイテムに対してng-repeat
タグのセットを作成するHTML文字列を( ng-href
を使用して)コンパイルします。<link />
要素のセットを<head>
タグに追加します。$rootScope
を使用して'$routeChangeStart'
イベントをリッスンします。すべての'$routeChangeStart'
イベントについて、「現在の」$$route
オブジェクト(ユーザーが残そうとしているルート)を取得し、その部分固有のcssファイルを<head>
タグから削除します。また、「次の」$$route
オブジェクト(ユーザーが移動しようとしているルート)を取得し、その部分固有のcssファイルを<head>
タグに追加します。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つのことで、必要なすべてがセットアップされ、可能な限りクリーンなコードで実行されます。
私がそうであったように、この問題に苦労しているかもしれない他の誰かを助けることを願っています。
@tennisgentのソリューションは素晴らしいです。しかし、私は少し限られていると思います。
Angularのモジュール性とカプセル化は、ルートを超えています。 Webがコンポーネントベースの開発に向かっている方法に基づいて、ディレクティブにもこれを適用することが重要です。
既にご存じのとおり、Angularでは、ページとコンポーネントにテンプレート(構造)とコントローラー(動作)を含めることができます。 AngularCSS は、最後に不足している部分を有効にします:スタイルシート(プレゼンテーション)を添付します。
完全なソリューションについては、AngularCSSを使用することをお勧めします。
ng-app
タグに<html>
を含める必要はありません。これは、同じページで複数のアプリを実行している場合に重要ですhttps://github.com/door3/angular-css
ここではいくつかの例を示します。
ルート
$routeProvider
.when('/page1', {
templateUrl: 'page1/page1.html',
controller: 'page1Ctrl',
/* Now you can bind css to routes */
css: 'page1/page1.css'
})
.when('/page2', {
templateUrl: 'page2/page2.html',
controller: 'page2Ctrl',
/* You can also enable features like bust cache, persist and preload */
css: {
href: 'page2/page2.css',
bustCache: true
}
})
.when('/page3', {
templateUrl: 'page3/page3.html',
controller: 'page3Ctrl',
/* This is how you can include multiple stylesheets */
css: ['page3/page3.css','page3/page3-2.css']
})
.when('/page4', {
templateUrl: 'page4/page4.html',
controller: 'page4Ctrl',
css: [
{
href: 'page4/page4.css',
persist: true
}, {
href: 'page4/page4.mobile.css',
/* Media Query support via window.matchMedia API
* This will only add the stylesheet if the breakpoint matches */
media: 'screen and (max-width : 768px)'
}, {
href: 'page4/page4.print.css',
media: 'print'
}
]
});
ディレクティブ
myApp.directive('myDirective', function () {
return {
restrict: 'E',
templateUrl: 'my-directive/my-directive.html',
css: 'my-directive/my-directive.css'
}
});
さらに、エッジの場合に$css
サービスを使用できます。
myApp.controller('pageCtrl', function ($scope, $css) {
// Binds stylesheet(s) to scope create/destroy events (recommended over add/remove)
$css.bind({
href: 'my-page/my-page.css'
}, $scope);
// Simply add stylesheet(s)
$css.add('my-page/my-page.css');
// Simply remove stylesheet(s)
$css.remove(['my-page/my-page.css','my-page/my-page2.css']);
// Remove all stylesheets
$css.removeAll();
});
AngularCSSの詳細については、こちらをご覧ください。
http://door3.com/insights/introducing-angularcss-css-demand-angularjs
$routeProvider
内のheadに新しいスタイルシートを追加できます。簡単にするために文字列を使用していますが、新しいリンク要素も作成するか、スタイルシートのサービスを作成できます
/* 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
の柔軟性が低いことです。
@ sz3、今日は十分面白い、私はあなたが達成しようとしていたものを正確にやらなければなりませんでした: '特定のCSSファイルをユーザーが特定のページにアクセスする'ときにのみロードします。そこで、上記のソリューションを使用しました。
しかし、私はあなたの最後の質問に答えるためにここにいます: 'どこに正確にコードを置くべきか。任意のアイデア? '
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'を読み込みます。
完全な説明は here にありますが、基本的に解決:は次の形式のオブジェクトを取得する必要があります
{
'key' : string or function()
}
'key'には好きな名前を付けることができます-私の場合は 'style'と呼びます。
次に、値には2つのオプションがあります。
文字列の場合、サービスのエイリアスです。
functionの場合、注入され、戻り値は依存関係として扱われます。
ここでの主なポイントは、コントローラーがインスタンス化されて$ routeChangeSuccessイベントが発生する前に、関数内のコードが実行されることです。
お役に立てば幸いです。
素晴らしいありがとう!! ui-routerで動作させるには、いくつかの調整を行う必要がありました。
var app = app || angular.module('app', []);
app.directive('head', ['$rootScope', '$compile', '$state', function ($rootScope, $compile, $state) {
return {
restrict: 'E',
link: function ($scope, elem, attrs, ctrls) {
var html = '<link rel="stylesheet" ng-repeat="(routeCtrl, cssUrl) in routeStyles" ng-href="{{cssUrl}}" />';
var el = $compile(html)($scope)
elem.append(el);
$scope.routeStyles = {};
function applyStyles(state, action) {
var sheets = state ? state.css : null;
if (state.parent) {
var parentState = $state.get(state.parent)
applyStyles(parentState, action);
}
if (sheets) {
if (!Array.isArray(sheets)) {
sheets = [sheets];
}
angular.forEach(sheets, function (sheet) {
action(sheet);
});
}
}
$rootScope.$on('$stateChangeStart', function (event, toState, toParams, fromState, fromParams) {
applyStyles(fromState, function(sheet) {
delete $scope.routeStyles[sheet];
console.log('>> remove >> ', sheet);
});
applyStyles(toState, function(sheet) {
$scope.routeStyles[sheet] = sheet;
console.log('>> add >> ', sheet);
});
});
}
}
}]);
特定のビューにCSSをappliedだけにする必要がある場合、コントローラー内でこの便利なスニペットを使用しています。
$("body").addClass("mystate");
$scope.$on("$destroy", function() {
$("body").removeClass("mystate");
});
これにより、状態が読み込まれるとクラスがbody
タグに追加され、状態が破棄されると(つまり、ページが変更されると)クラスが削除されます。これにより、CSSのみをアプリケーションの1つの状態に適用する必要があるという私の関連する問題が解決されます。
'use strict'; angular.module( 'app').run(['$ rootScope'、 '$ state'、 '$ stateParams'、function($ rootScope、$ state、$ stateParams){$ rootScope。$ state = $ state; $ rootScope 。$ stateParams = $ stateParams;}]).config(['$ stateProvider'、 '$ urlRouterProvider'、function($ stateProvider、$ urlRouterProvider){
$urlRouterProvider
.otherwise('/app/dashboard');
$stateProvider
.state('app', {
abstract: true,
url: '/app',
templateUrl: 'views/layout.html'
})
.state('app.dashboard', {
url: '/dashboard',
templateUrl: 'views/dashboard.html',
ncyBreadcrumb: {
label: 'Dashboard',
description: ''
},
resolve: {
deps: [
'$ocLazyLoad',
function($ocLazyLoad) {
return $ocLazyLoad.load({
serie: true,
files: [
'lib/jquery/charts/sparkline/jquery.sparkline.js',
'lib/jquery/charts/easypiechart/jquery.easypiechart.js',
'lib/jquery/charts/flot/jquery.flot.js',
'lib/jquery/charts/flot/jquery.flot.resize.js',
'lib/jquery/charts/flot/jquery.flot.pie.js',
'lib/jquery/charts/flot/jquery.flot.tooltip.js',
'lib/jquery/charts/flot/jquery.flot.orderBars.js',
'app/controllers/dashboard.js',
'app/directives/realtimechart.js'
]
});
}
]
}
})
.state('ram', {
abstract: true,
url: '/ram',
templateUrl: 'views/layout-ram.html'
})
.state('ram.dashboard', {
url: '/dashboard',
templateUrl: 'views/dashboard-ram.html',
ncyBreadcrumb: {
label: 'test'
},
resolve: {
deps: [
'$ocLazyLoad',
function($ocLazyLoad) {
return $ocLazyLoad.load({
serie: true,
files: [
'lib/jquery/charts/sparkline/jquery.sparkline.js',
'lib/jquery/charts/easypiechart/jquery.easypiechart.js',
'lib/jquery/charts/flot/jquery.flot.js',
'lib/jquery/charts/flot/jquery.flot.resize.js',
'lib/jquery/charts/flot/jquery.flot.pie.js',
'lib/jquery/charts/flot/jquery.flot.tooltip.js',
'lib/jquery/charts/flot/jquery.flot.orderBars.js',
'app/controllers/dashboard.js',
'app/directives/realtimechart.js'
]
});
}
]
}
})
);