如何在AngularJS中包含视图/部分特定样式?

时间:2022-05-01 11:24:58

What is the proper/accepted way to use separate stylesheets for the various views my application uses?

对于我的应用程序使用的各种视图,使用独立样式表的合适/可接受的方式是什么?

Currently I'm placing a link element in the view/partial's html at the top but I've been told this is bad practice even though all modern browsers support it but I can see why it's frowned upon.

目前,我正在视图/部分的html顶部放置一个链接元素,但有人告诉我,这是一种不好的做法,尽管所有现代浏览器都支持它,但我能理解为什么它不受欢迎。

The other possibility is placing the separate stylesheets in my index.html's head but I would like it to only load the stylesheet if its view is being loaded in the name of performance.

另一种可能是将单独的样式表放在索引中。但是我希望它只在以性能的名义加载视图时才加载样式表。

Is this bad practice since styling won't take effect until after the css is loaded form the server, leading to a quick flash of unformatted content in a slow browser? I have yet to witness this although I'm testing it locally.

这是不是不好的做法,因为样式化在从服务器加载css之后才会生效,导致在慢速浏览器中快速闪现未格式化的内容?虽然我正在本地测试,但我还没有看到这一点。

Is there a way to load the CSS through the object passed to Angular's $routeProvider.when?

有没有一种方法可以通过传递给棱角的$ routeprovidern的对象加载CSS ?

Thanks in advance!

提前谢谢!

7 个解决方案

#1


145  

I know this question is old now, but after doing a ton of research on various solutions to this problem, I think I may have come up with a better solution.

我知道这个问题现在已经过时了,但在对这个问题的各种解决方案进行了大量研究之后,我想我可能已经找到了一个更好的解决方案。

UPDATE 1: Since posting this answer, I have added all of this code to a simple service that I have posted to GitHub. The repo is located here. Feel free to check it out for more info.

更新1:自从发布这个答案以来,我已经将所有这些代码添加到一个简单的服务中,我已经将它发布到GitHub上。repo在这里。想了解更多信息,请随时查阅。

UPDATE 2: This answer is great if all you need is a lightweight solution for pulling in stylesheets for your routes. If you want a more complete solution for managing on-demand stylesheets throughout your application, you may want to checkout Door3's AngularCSS project. It provides much more fine-grained functionality.

更新2:如果您所需要的只是为您的路由拉入样式表的轻量级解决方案,那么这个答案是很好的。如果您想要在整个应用程序中管理按需样式表的更完整的解决方案,您可能需要检查Door3的AngularCSS项目。它提供了更细粒度的功能。

In case anyone in the future is interested, here's what I came up with:

如果将来有人感兴趣的话,以下是我的想法:

1. Create a custom directive for the <head> element:

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;
                        });
                    }
                });
            }
        };
    }
]);

This directive does the following things:

本指令的作用如下:

  1. It compiles (using $compile) an html string that creates a set of <link /> tags for every item in the scope.routeStyles object using ng-repeat and ng-href.
  2. 它编译(使用$compile)一个html字符串,该字符串为范围中的每个条目创建一组 标记。使用ng-repeat和ng-href的routeStyles对象。
  3. It appends that compiled set of <link /> elements to the <head> tag.
  4. 它将编译好的 元素集附加到标记。
  5. It then uses the $rootScope to listen for '$routeChangeStart' events. For every '$routeChangeStart' event, it grabs the "current" $$route object (the route that the user is about to leave) and removes its partial-specific css file(s) from the <head> tag. It also grabs the "next" $$route object (the route that the user is about to go to) and adds any of its partial-specific css file(s) to the <head> tag.
  6. 然后它使用$rootScope来侦听“$routeChangeStart”事件。对于每一个“$routeChangeStart”事件,它会抓取“当前”$$route对象(用户将要离开的路由),并从标记中移除它的特定于部分的css文件。它还获取“next”$route对象(用户将要访问的路由),并将其部分特定的css文件添加到标记中。
  7. And the ng-repeat part of the compiled <link /> tag handles all of the adding and removing of the page-specific stylesheets based on what gets added to or removed from the scope.routeStyles object.
  8. 编译后的 标记的ng-repeat部分根据添加到范围或从范围中删除的内容来处理所有与页面相关的样式表的添加和删除。routeStyles对象。

Note: this requires that your ng-app attribute is on the <html> element, not on <body> or anything inside of <html>.

注意:这要求您的ng-app属性在元素上,而不是在或中的任何内容上。

2. Specify which stylesheets belong to which routes using the $routeProvider:

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']
        })
}]);

This config adds a custom css property to the object that is used to setup each page's route. That object gets passed to each '$routeChangeStart' event as .$$route. So when listening to the '$routeChangeStart' event, we can grab the css property that we specified and append/remove those <link /> tags as needed. Note that specifying a css property on the route is completely optional, as it was omitted from the '/some/route/2' example. If the route doesn't have a css property, the <head> directive will simply do nothing for that route. Note also that you can even have multiple page-specific stylesheets per route, as in the '/some/route/3' example above, where the css property is an array of relative paths to the stylesheets needed for that route.

此配置将自定义css属性添加到用于设置每个页面的路由的对象中。该对象被传递到每个“$routeChangeStart”事件,如$route。因此,在听“$routeChangeStart”事件时,我们可以获取指定的css属性,并在需要时附加/删除那些 标记。注意,在路由上指定css属性是完全可选的,因为它在“/some/route/2”示例中被省略了。如果路由没有css属性,则指令将对该路由不做任何操作。还要注意,您甚至可以在每个路由上都有多个页面特定的样式表,如上面的“/some/route/3”示例,其中css属性是该路径所需的样式表的相对路径数组。

3. You're done Those two things setup everything that was needed and it does it, in my opinion, with the cleanest code possible.

3所示。您完成了这两件事,设置了所有需要的东西,在我看来,它使用了尽可能干净的代码。

Hope that helps someone else who might be struggling with this issue as much as I was.

希望这能帮助那些和我一样在这个问题上挣扎的人。

#2


33  

@tennisgent's solution is great. However, I think is a little limited.

@tennisgent的解决方案是伟大的。然而,我认为是有限的。

Modularity and Encapsulation in Angular goes beyond routes. Based on the way the web is moving towards component-based development, it is important to apply this in directives as well.

角度的模块化和封装超越了路径。基于web正朝着基于组件的开发方向发展的方式,在指令中应用这一点也很重要。

As you already know, in Angular we can include templates (structure) and controllers (behavior) in pages and components. AngularCSS enables the last missing piece: attaching stylesheets (presentation).

正如您已经知道的,在角度上,我们可以在页面和组件中包含模板(结构)和控制器(行为)。AngularCSS支持最后一个缺失的部分:附加样式表(表示)。

For a full solution I suggest using AngularCSS.

对于完整的解决方案,我建议使用AngularCSS。

  1. Supports Angular's ngRoute, UI Router, directives, controllers and services.
  2. 支持角的ngRoute, UI路由器,指令,控制器和服务。
  3. Doesn't required to have ng-app in the <html> tag. This is important when you have multiple apps running on the same page
  4. 不需要在标签中包含ng-app。当在同一个页面上运行多个应用程序时,这一点很重要
  5. You can customize where the stylesheets are injected: head, body, custom selector, etc...
  6. 您可以自定义样式表注入的位置:head、body、custom selector等。
  7. Supports preloading, persisting and cache busting
  8. 支持预加载、持久化和缓存崩溃
  9. Supports media queries and optimizes page load via matchMedia API
  10. 支持媒体查询并通过matchMedia API优化页面加载

https://github.com/door3/angular-css

https://github.com/door3/angular-css

Here are some examples:

下面是一些例子:

Routes

路线

  $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'
        }
      ]
    });

Directives

指令

myApp.directive('myDirective', function () {
  return {
    restrict: 'E',
    templateUrl: 'my-directive/my-directive.html',
    css: 'my-directive/my-directive.css'
  }
});

Additionally, you can use the $css service for edge cases:

此外,您还可以使用$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();

});

You can read more about AngularCSS here:

你可以在这里阅读更多关于天使的信息:

http://door3.com/insights/introducing-angularcss-css-demand-angularjs

http://door3.com/insights/introducing-angularcss-css-demand-angularjs

#3


13  

Could append a new stylesheet to head within $routeProvider. For simplicity am using a string but could create new link element also, or create a service for stylesheets

可以在$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">');
}

Biggest benefit of prelaoding in page is any background images will already exist, and less lieklyhood of FOUC

在页面中预览的最大好处是任何背景图像都已经存在,而且FOUC的lieklyhood也更少

#4


4  

@sz3, funny enough today I had to do exactly what you were trying to achieve: 'load a specific CSS file only when a user access' a specific page. So I used the solution above.

@sz3,有趣的是,今天我不得不做你想做的事情:“只有当用户访问特定页面时才加载特定的CSS文件”。我用了上面的解。

But I am here to answer your last question: 'where exactly should I put the code. Any ideas?'

但我在这里回答你的最后一个问题:‘我应该把密码确切地放在哪里?有什么想法?”

You were right including the code into the resolve, but you need to change a bit the format.

您将代码包含到解析中是正确的,但是您需要稍微更改格式。

Take a look at the code below:

看看下面的代码:

.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">');
      }
    }
  }
})

I've just tested and it's working fine, it injects the html and it loads my 'home.css' only when I hit the '/home' route.

我刚刚测试过,它运行得很好,它注入了html并加载了我的“家”。只有当我到达“/home”路径时才使用css。

Full explanation can be found here, but basically resolve: should get an object in the format

在这里可以找到完整的解释,但是基本的解析是:应该以这种格式获取一个对象

{
  'key' : string or function()
} 

You can name the 'key' anything you like - in my case I called 'style'.

你可以给“key”取任何你喜欢的名字——在我的例子里,我叫它“style”。

Then for the value you have two options:

那么对于值,你有两个选择:

  • If it's a string, then it is an alias for a service.

    如果是字符串,那么它就是服务的别名。

  • If it's function, then it is injected and the return value is treated as the dependency.

    如果是函数,则将其注入,并将返回值视为依赖项。

The main point here is that the code inside the function is going to be executed before before the controller is instantiated and the $routeChangeSuccess event is fired.

这里的要点是,在实例化控制器并触发$routeChangeSuccess事件之前,函数中的代码将被执行。

Hope that helps.

希望有帮助。

#5


2  

Awesome, thank you!! Just had to make a few adjustments to get it working with ui-router:

太棒了,谢谢你! !只需做一些调整,让它与ui-路由器一起工作:

    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);
                });
            });
        }
    }
}]);

#6


0  

If you only need your CSS to be applied to one specific view, I'm using this handy snippet inside my controller:

如果你只需要你的CSS应用到一个特定的视图,我正在我的控制器中使用这个方便的代码片段:

$("body").addClass("mystate");

$scope.$on("$destroy", function() {
  $("body").removeClass("mystate"); 
});

This will add a class to my body tag when the state loads, and remove it when the state is destroyed (i.e. someone changes pages). This solves my related problem of only needing CSS to be applied to one state in my application.

这将在状态加载时向我的body标记添加一个类,并在状态被破坏时删除它(例如,有人更改页面)。这解决了我在应用程序中只需要将CSS应用到一个状态的相关问题。

#7


0  

'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) {

使用严格的;模块('app') .run(['$rootScope', '$state', '$stateParams', function($rootScope, $state, $stateParams) {$rootScope)。$ = $状态;rootScope美元。stateParams = stateParams美元;) .config(['$stateProvider', '$urlRouterProvider',函数($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'
                                    ]
                                });
                            }
                        ]
                    }
                })
                 );

#1


145  

I know this question is old now, but after doing a ton of research on various solutions to this problem, I think I may have come up with a better solution.

我知道这个问题现在已经过时了,但在对这个问题的各种解决方案进行了大量研究之后,我想我可能已经找到了一个更好的解决方案。

UPDATE 1: Since posting this answer, I have added all of this code to a simple service that I have posted to GitHub. The repo is located here. Feel free to check it out for more info.

更新1:自从发布这个答案以来,我已经将所有这些代码添加到一个简单的服务中,我已经将它发布到GitHub上。repo在这里。想了解更多信息,请随时查阅。

UPDATE 2: This answer is great if all you need is a lightweight solution for pulling in stylesheets for your routes. If you want a more complete solution for managing on-demand stylesheets throughout your application, you may want to checkout Door3's AngularCSS project. It provides much more fine-grained functionality.

更新2:如果您所需要的只是为您的路由拉入样式表的轻量级解决方案,那么这个答案是很好的。如果您想要在整个应用程序中管理按需样式表的更完整的解决方案,您可能需要检查Door3的AngularCSS项目。它提供了更细粒度的功能。

In case anyone in the future is interested, here's what I came up with:

如果将来有人感兴趣的话,以下是我的想法:

1. Create a custom directive for the <head> element:

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;
                        });
                    }
                });
            }
        };
    }
]);

This directive does the following things:

本指令的作用如下:

  1. It compiles (using $compile) an html string that creates a set of <link /> tags for every item in the scope.routeStyles object using ng-repeat and ng-href.
  2. 它编译(使用$compile)一个html字符串,该字符串为范围中的每个条目创建一组 标记。使用ng-repeat和ng-href的routeStyles对象。
  3. It appends that compiled set of <link /> elements to the <head> tag.
  4. 它将编译好的 元素集附加到标记。
  5. It then uses the $rootScope to listen for '$routeChangeStart' events. For every '$routeChangeStart' event, it grabs the "current" $$route object (the route that the user is about to leave) and removes its partial-specific css file(s) from the <head> tag. It also grabs the "next" $$route object (the route that the user is about to go to) and adds any of its partial-specific css file(s) to the <head> tag.
  6. 然后它使用$rootScope来侦听“$routeChangeStart”事件。对于每一个“$routeChangeStart”事件,它会抓取“当前”$$route对象(用户将要离开的路由),并从标记中移除它的特定于部分的css文件。它还获取“next”$route对象(用户将要访问的路由),并将其部分特定的css文件添加到标记中。
  7. And the ng-repeat part of the compiled <link /> tag handles all of the adding and removing of the page-specific stylesheets based on what gets added to or removed from the scope.routeStyles object.
  8. 编译后的 标记的ng-repeat部分根据添加到范围或从范围中删除的内容来处理所有与页面相关的样式表的添加和删除。routeStyles对象。

Note: this requires that your ng-app attribute is on the <html> element, not on <body> or anything inside of <html>.

注意:这要求您的ng-app属性在元素上,而不是在或中的任何内容上。

2. Specify which stylesheets belong to which routes using the $routeProvider:

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']
        })
}]);

This config adds a custom css property to the object that is used to setup each page's route. That object gets passed to each '$routeChangeStart' event as .$$route. So when listening to the '$routeChangeStart' event, we can grab the css property that we specified and append/remove those <link /> tags as needed. Note that specifying a css property on the route is completely optional, as it was omitted from the '/some/route/2' example. If the route doesn't have a css property, the <head> directive will simply do nothing for that route. Note also that you can even have multiple page-specific stylesheets per route, as in the '/some/route/3' example above, where the css property is an array of relative paths to the stylesheets needed for that route.

此配置将自定义css属性添加到用于设置每个页面的路由的对象中。该对象被传递到每个“$routeChangeStart”事件,如$route。因此,在听“$routeChangeStart”事件时,我们可以获取指定的css属性,并在需要时附加/删除那些 标记。注意,在路由上指定css属性是完全可选的,因为它在“/some/route/2”示例中被省略了。如果路由没有css属性,则指令将对该路由不做任何操作。还要注意,您甚至可以在每个路由上都有多个页面特定的样式表,如上面的“/some/route/3”示例,其中css属性是该路径所需的样式表的相对路径数组。

3. You're done Those two things setup everything that was needed and it does it, in my opinion, with the cleanest code possible.

3所示。您完成了这两件事,设置了所有需要的东西,在我看来,它使用了尽可能干净的代码。

Hope that helps someone else who might be struggling with this issue as much as I was.

希望这能帮助那些和我一样在这个问题上挣扎的人。

#2


33  

@tennisgent's solution is great. However, I think is a little limited.

@tennisgent的解决方案是伟大的。然而,我认为是有限的。

Modularity and Encapsulation in Angular goes beyond routes. Based on the way the web is moving towards component-based development, it is important to apply this in directives as well.

角度的模块化和封装超越了路径。基于web正朝着基于组件的开发方向发展的方式,在指令中应用这一点也很重要。

As you already know, in Angular we can include templates (structure) and controllers (behavior) in pages and components. AngularCSS enables the last missing piece: attaching stylesheets (presentation).

正如您已经知道的,在角度上,我们可以在页面和组件中包含模板(结构)和控制器(行为)。AngularCSS支持最后一个缺失的部分:附加样式表(表示)。

For a full solution I suggest using AngularCSS.

对于完整的解决方案,我建议使用AngularCSS。

  1. Supports Angular's ngRoute, UI Router, directives, controllers and services.
  2. 支持角的ngRoute, UI路由器,指令,控制器和服务。
  3. Doesn't required to have ng-app in the <html> tag. This is important when you have multiple apps running on the same page
  4. 不需要在标签中包含ng-app。当在同一个页面上运行多个应用程序时,这一点很重要
  5. You can customize where the stylesheets are injected: head, body, custom selector, etc...
  6. 您可以自定义样式表注入的位置:head、body、custom selector等。
  7. Supports preloading, persisting and cache busting
  8. 支持预加载、持久化和缓存崩溃
  9. Supports media queries and optimizes page load via matchMedia API
  10. 支持媒体查询并通过matchMedia API优化页面加载

https://github.com/door3/angular-css

https://github.com/door3/angular-css

Here are some examples:

下面是一些例子:

Routes

路线

  $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'
        }
      ]
    });

Directives

指令

myApp.directive('myDirective', function () {
  return {
    restrict: 'E',
    templateUrl: 'my-directive/my-directive.html',
    css: 'my-directive/my-directive.css'
  }
});

Additionally, you can use the $css service for edge cases:

此外,您还可以使用$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();

});

You can read more about AngularCSS here:

你可以在这里阅读更多关于天使的信息:

http://door3.com/insights/introducing-angularcss-css-demand-angularjs

http://door3.com/insights/introducing-angularcss-css-demand-angularjs

#3


13  

Could append a new stylesheet to head within $routeProvider. For simplicity am using a string but could create new link element also, or create a service for stylesheets

可以在$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">');
}

Biggest benefit of prelaoding in page is any background images will already exist, and less lieklyhood of FOUC

在页面中预览的最大好处是任何背景图像都已经存在,而且FOUC的lieklyhood也更少

#4


4  

@sz3, funny enough today I had to do exactly what you were trying to achieve: 'load a specific CSS file only when a user access' a specific page. So I used the solution above.

@sz3,有趣的是,今天我不得不做你想做的事情:“只有当用户访问特定页面时才加载特定的CSS文件”。我用了上面的解。

But I am here to answer your last question: 'where exactly should I put the code. Any ideas?'

但我在这里回答你的最后一个问题:‘我应该把密码确切地放在哪里?有什么想法?”

You were right including the code into the resolve, but you need to change a bit the format.

您将代码包含到解析中是正确的,但是您需要稍微更改格式。

Take a look at the code below:

看看下面的代码:

.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">');
      }
    }
  }
})

I've just tested and it's working fine, it injects the html and it loads my 'home.css' only when I hit the '/home' route.

我刚刚测试过,它运行得很好,它注入了html并加载了我的“家”。只有当我到达“/home”路径时才使用css。

Full explanation can be found here, but basically resolve: should get an object in the format

在这里可以找到完整的解释,但是基本的解析是:应该以这种格式获取一个对象

{
  'key' : string or function()
} 

You can name the 'key' anything you like - in my case I called 'style'.

你可以给“key”取任何你喜欢的名字——在我的例子里,我叫它“style”。

Then for the value you have two options:

那么对于值,你有两个选择:

  • If it's a string, then it is an alias for a service.

    如果是字符串,那么它就是服务的别名。

  • If it's function, then it is injected and the return value is treated as the dependency.

    如果是函数,则将其注入,并将返回值视为依赖项。

The main point here is that the code inside the function is going to be executed before before the controller is instantiated and the $routeChangeSuccess event is fired.

这里的要点是,在实例化控制器并触发$routeChangeSuccess事件之前,函数中的代码将被执行。

Hope that helps.

希望有帮助。

#5


2  

Awesome, thank you!! Just had to make a few adjustments to get it working with ui-router:

太棒了,谢谢你! !只需做一些调整,让它与ui-路由器一起工作:

    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);
                });
            });
        }
    }
}]);

#6


0  

If you only need your CSS to be applied to one specific view, I'm using this handy snippet inside my controller:

如果你只需要你的CSS应用到一个特定的视图,我正在我的控制器中使用这个方便的代码片段:

$("body").addClass("mystate");

$scope.$on("$destroy", function() {
  $("body").removeClass("mystate"); 
});

This will add a class to my body tag when the state loads, and remove it when the state is destroyed (i.e. someone changes pages). This solves my related problem of only needing CSS to be applied to one state in my application.

这将在状态加载时向我的body标记添加一个类,并在状态被破坏时删除它(例如,有人更改页面)。这解决了我在应用程序中只需要将CSS应用到一个状态的相关问题。

#7


0  

'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) {

使用严格的;模块('app') .run(['$rootScope', '$state', '$stateParams', function($rootScope, $state, $stateParams) {$rootScope)。$ = $状态;rootScope美元。stateParams = stateParams美元;) .config(['$stateProvider', '$urlRouterProvider',函数($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'
                                    ]
                                });
                            }
                        ]
                    }
                })
                 );