Как включить вид / частичный конкретный стиль в AngularJS


каков правильный / принятый способ использования отдельных таблиц стилей для различных представлений, которые использует мое приложение?

В настоящее время я помещаю элемент ссылки в html view/partial в верхней части, но мне сказали, что это плохая практика, хотя все современные браузеры поддерживают ее, но я вижу, почему она нахмурилась.

другая возможность-это размещение отдельных таблиц стилей в моем индексе.html-это head но я хотел бы, чтобы он загружал только таблицу стилей, если его представление загружается во имя производительности.

это плохая практика, так как стиль не вступит в силу до тех пор, пока css не будет загружен с сервера, что приведет к быстрой вспышке неформатированного контента в медленном браузере? Я еще не видел этого, хотя я тестирую его локально.

есть ли способ загрузить CSS через объект, переданный в Angular $routeProvider.when?

спасибо заранее!

7 130

7 ответов:

я знаю, что этот вопрос уже устарел, но после проведения тонны исследований по различным решениям этой проблемы, я думаю, что, возможно, я придумал лучшее решение.

обновление 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 объект (маршрут, который пользователь собирается оставить) и удаляет его частичный специфический css-файл(ы) из <head> тег. Он также захватывает "следующий"$$route объект (маршрут, по которому пользователь собирается перейти) и добавляет любой из его частичных специфичных css-файлов в <head> тег.
  4. и ng-repeat часть компиляции <link /> тег обрабатывает все добавления и удаления страниц конкретных таблиц стилей на основе того, что добавляется или удаляется из scope.routeStyles объект.

Примечание:это требует, чтобы ваш на <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 property, the

@tennisgent's solution is great. Однако, я думаю, это немного ограничено.

модульность и инкапсуляция в Angular выходит за рамки маршрутов. Исходя из того, как интернет движется к компонентной разработке, важно применять это и в директивах.

как вы уже знаете, в Angular мы можем включать шаблоны (структуру) и контроллеры (поведение) в страницы и компоненты. AngularCSS включает последнюю недостающую часть: прикрепление таблицы стилей (презентация).

для полного решения я предлагаю использовать AngularCSS.

  1. поддерживает Ngroute Angular, маршрутизатор UI, директивы, контроллеры и службы.
  2. не требуется ng-app на <html> тег. Это важно, когда у вас есть несколько приложений, работающих на одной странице
  3. вы можете настроить, где вводятся таблицы стилей: голова, тело, пользовательский селектор и т. д...
  4. поддержка предварительной загрузки, сохранение и кэш перебора
  5. поддерживает медиа-запросы и оптимизирует загрузку страниц через matchMedia API

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. Для простоты я использую строку, но также могу создать новый элемент ссылки или создать сервис для таблиц стилей

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

самое большое преимущество предварительного кодирования на странице-это то, что любые фоновые изображения уже будут существовать, и меньше lieklyhood FOUC

@sz3, довольно смешно сегодня я должен был сделать именно то, что вы пытались достичь: 'загрузите определенный файл CSS только при доступе пользователя' конкретной страницы. Поэтому я использовал решение выше.

потрясающе, спасибо!! Просто пришлось сделать несколько настроек, чтобы заставить его работать с 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, чтобы быть применяется для одного конкретного представления, я использую этот удобный фрагмент внутри моего контроллера:

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

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

Это добавит класс к моему body тег, когда состояние загружается, и удалить его, когда состояние уничтожается (т. е. кто-то меняет страницы). Это решает мою связанную проблему необходимости применения CSS только к одному состоянию в моем приложении.

'use strict'; угловатый.модуль('приложение') .бежать( [ '$rootScope', '$state', '$stateParams', функция ($rootScope, $state, $stateParams) { $rootScope.$состояние = $государству; $rootScope.$stateParams = $stateParams; } ] ) .конфиг( [ '$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'
                                    ]
                                });
                            }
                        ]
                    }
                })
                 );