133 votes

Comment inclure un style spécifique à la vue/partiel dans AngularJS

Quelle est la manière correcte/acceptée d'utiliser des feuilles de style distinctes pour les différentes vues que mon application utilise ?

Actuellement, je place un élément de lien dans le html de la vue/partiel en haut, mais on m'a dit que c'était une mauvaise pratique, même si tous les navigateurs modernes le supportent, mais je peux comprendre pourquoi c'est mal vu.

L'autre possibilité est de placer les feuilles de style séparées dans le fichier index.html de mon site. head mais je voudrais qu'il ne charge la feuille de style que si sa vue est chargée au nom de la performance.

S'agit-il d'une mauvaise pratique puisque le style ne prendra effet qu'après le chargement du css depuis le serveur, ce qui entraînera un flash rapide de contenu non formaté dans un navigateur lent ? Je n'ai pas encore été témoin de ce phénomène, bien que je le teste localement.

Existe-t-il un moyen de charger le CSS par l'intermédiaire de l'objet transmis à la méthode d'Angular $routeProvider.when ?

Merci d'avance !

34voto

castillo.io Points 913

La solution de @tennisgent est excellente. Cependant, je pense qu'elle est un peu limitée.

La modularité et l'encapsulation dans Angular vont au-delà des routes. Compte tenu de la manière dont le web évolue vers un développement basé sur les composants, il est important de l'appliquer également dans les directives.

Comme vous le savez déjà, en Angular, nous pouvons inclure des modèles (structure) et des contrôleurs (comportement) dans les pages et les composants. AngularCSS permet la dernière pièce manquante : l'attachement des feuilles de style (présentation).

Pour une solution complète, je suggère d'utiliser AngularCSS.

  1. Prend en charge ngRoute, UI Router, les directives, les contrôleurs et les services d'Angular.
  2. Il n'est pas nécessaire d'avoir ng-app dans le <html> étiquette. C'est important lorsque plusieurs applications fonctionnent sur la même page.
  3. Vous pouvez personnaliser l'endroit où les feuilles de style sont injectées : head, body, sélecteur personnalisé, etc...
  4. Prise en charge du préchargement, de la persistance et de la suppression du cache.
  5. Prise en charge des requêtes média et optimisation du chargement des pages via l'API matchMedia

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

Voici quelques exemples :

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

En outre, vous pouvez utiliser le $css service pour les cas limites :

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();

});

Vous pouvez en savoir plus sur AngularCSS ici :

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

13voto

charlietfl Points 41873

Pourrait ajouter une nouvelle feuille de style à la tête dans $routeProvider . Pour des raisons de simplicité, j'utilise une chaîne de caractères, mais je pourrais aussi créer un nouvel élément de lien ou un service pour les feuilles de style.

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

Le principal avantage du prélaodage dans la page est que toutes les images d'arrière-plan existent déjà et qu'il y a moins de risques que les images d'arrière-plan ne soient pas utilisées. FOUC

5voto

dluz Points 1821

@sz3, c'est drôle, aujourd'hui j'ai dû faire exactement ce que vous essayez de faire : charger un fichier CSS spécifique uniquement lorsqu'un utilisateur accède au site. ' une page spécifique. J'ai donc utilisé la solution ci-dessus.

Mais je suis ici pour répondre à votre dernière question : " ". où dois-je mettre le code exactement ? Avez-vous des idées ? ?'

Vous aviez raison d'inclure le code dans le résoudre mais vous devez changer un peu le format.

Jetez un coup d'œil au code ci-dessous :

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

Je viens de le tester et il fonctionne bien. il injecte le code html et charge mon fichier 'home.css' uniquement lorsque j'accède à la route '/home'.

Une explication complète peut être trouvée aquí mais en gros résolution : devrait obtenir un objet au format

{
  'key' : string or function()
} 

Vous pouvez nommer le ' clé comme vous le souhaitez - dans mon cas, j'ai appelé style '.

Ensuite, pour la valeur, vous avez deux options :

  • Si c'est un string alors il s'agit d'un alias pour un service.

  • Si c'est fonction alors il est injecté et la valeur de retour est traitée. comme une dépendance.

Le point principal ici est que le code à l'intérieur de la fonction va être exécuté avant que le contrôleur soit instancié et que l'événement $routeChangeSuccess soit déclenché.

J'espère que cela vous aidera.

2voto

CraigM Points 50

Génial, merci ! J'ai juste dû faire quelques ajustements pour que ça fonctionne avec 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);
                });
            });
        }
    }
}]);

1voto

Matt Points 34

Si vous avez seulement besoin que votre CSS soit appliqué à une vue spécifique, j'utilise cet extrait pratique dans mon contrôleur :

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

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

Cela va ajouter une classe à mon body lorsque l'état se charge, et la supprimer lorsque l'état est détruit (c'est-à-dire lorsque quelqu'un change de page). Cela résout mon problème connexe, à savoir que le CSS ne doit être appliqué qu'à un seul état dans mon application.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X