一尘不染

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

angularjs

对我的应用程序使用的各种视图使用单独的样式表的正确/可接受的方法是什么?

目前,我在视图/部分的html顶部放置了一个link元素,但有人告诉我这是一种不好的做法,即使所有现代浏览器都支持它,但我可以理解为什么对此不满意。

另一种可能性是将单独的样式表放置在我的index.html中,head但是我希望它仅在以性能名义加载其视图时才加载样式表。

这是不好的做法吗,因为样式只有在将css从服务器加载之后才会生效,从而导致缓慢的浏览器中未格式化内容的快速闪烁?尽管我正在本地进行测试,但我还没有目睹这一点。

有没有一种方法可以通过传递给Angular的对象加载CSS $routeProvider.when

提前致谢!


阅读 186

收藏
2020-07-04

共1个答案

一尘不染

我知道这个问题现在已经很老了,但是在对这个问题的各种解决方案进行了大量研究之后,我认为我可能已经提出了一个更好的解决方案。

更新1:
自发布此答案以来,我已将所有这些代码添加到我发布到GitHub的简单服务中。仓库位于此处。随时查看更多信息。

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

该指令执行以下操作:

  1. 它编译(使用$compile)一个html字符串,该字符串使用和<link />scope.routeStyles对象中的每个项目创建一组标记。ng-repeat``ng-href
  2. 它将编译后的<link />元素集附加到<head>标签。
  3. 然后,它使用$rootScope侦听'$routeChangeStart'事件。对于每个'$routeChangeStart'事件,它都会捕获“当前” $$route对象(用户将要离开的路线),并从<head>标记中删除其部分特定的css文件。它还捕获“下一个” $$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.完成工作 我认为,这两件事设置了所需的一切,并且使用了最干净的代码来完成了它。

希望这对我可能一直在努力解决此问题的其他人有所帮助。

2020-07-04