1
votes

Angular: Comment ajouter du CSS global (par exemple au corps), mais uniquement pour une page spécifique?

Comment puis-je ajouter un CSS distinct pour une page dans Angular?

C'est le CSS dont j'ai besoin, selon Comment supprimer l'URL de la page d'impression? :

  encapsulation: ViewEncapsulation.None

   ...      

  constructor(private renderer: Renderer2) {
    this.renderer.addClass(document.body, 'special-print');
   }

  ngOnDestroy() {
    this.renderer.removeClass(document.body, 'special-print');
  }
  ....
  ....
  ....
  @media print{
    @page{
        margin:0;
    }
    body.special-print{
        margin:30px;
    }
  }

Mais mettre du CSS dans le composant avec ::ng-deep ou ViewEncapsulation.None pas ici, car lorsque vous vous éloignez d'une page, le CSS de la page n'est pas supprimé.

J'ai ajouté un Stackblitz , ce qui explique clairement le problème.


J'ai trouvé une solution potentielle, mais cela ne fonctionne pas:

@media print{
    @page{
        margin:0;
    }
    body{
        margin:30px;
    }
}

Pourquoi ça ne marche pas:

Bien que cela aiderait avec <body> CSS, cela n'aiderait pas avec @page CSS. Peut-être que la question serait mieux résumée comme suit: «Comment ajouter du CSS global, mais le supprimer lorsque nous quittons la page?».


4 commentaires

Essayez d'utiliser la feuille de style des composants pour un style distinct de page spécifique, qui n'effectuera pas les styles globalement


Suivez ensuite la méthode de liaison / encapsulation mentionnée dans ce stackoverflow.com/questions/34881401/...


@Awais Cette solution fonctionnerait pour <body> , mais elle ne fonctionnerait pas pour d'autres CSS globaux comme @page . (Si vous regardez le CSS que j'ai écrit dans mon article, vous verrez ce que je veux dire.)


Vous pouvez consulter cette réponse à une question similaire que j'ai posée à stackoverflow.com/a/64672874/13680115 . Je pense que la réponse devrait également fonctionner pour votre cas, cela a fonctionné pour moi


4 Réponses :


-1
votes

Vous pouvez ajouter différents fichiers css dans le composant (par exemple, app-task.component.ts):

@Component({
  selector: 'app-task',
  templateUrl: './app-task.component.html',
  styleUrls: ['./app-task.component.scss', './styles2.scss', './styles3.scss']
})

Dans cet exemple, les fichiers de style sont dans le même dossier que le composant, mais ce n'est pas la meilleure option: vous devez par exemple placer les fichiers dans des assets. Faites également attention au filetage des styles, puisque le premier que vous mettez sera placé avant le second (évidemment).


4 commentaires

Le problème est que ces styles ne sont pas supprimés lorsque la page est déchargée. J'ai besoin d'un moyen d'ajouter des styles qui ne persisteront PAS de page en page.


Ce que fait Angular, c'est qu'il étend le CSS à un composant particulier. Par exemple, si je travaille avec app-mybutton , alors angular ajoutera automatiquement app-mybutton à tous les CSS écrits dans ce composant. Ce qui est idéal pour garder le code propre, mais pas très utile lorsque j'essaie de modifier le <body> .


(Eh bien, pour être plus clair, cela ajoute en fait des trucs de [ng-content] au CSS, mais le [ng-content] conserve effectivement tout le CSS que vous affectez uniquement à ce composant.)


J'ai créé un Stackblitz pour mieux montrer le problème.



0
votes

Ne changez pas tout le corps de la pomme. Au lieu de cela, il y a quelques changements à apporter.

  1. Dans le composant d'application, maintenez une valeur booléenne indiquant si vous êtes ou non sur apple et utilisez ngClass pour la classe définie dans scss.

  2. Suivez l'itinéraire sur lequel vous vous trouvez dans appComponent et définissez isApple en conséquence

  3. Ajoutez un div autour de tout votre html, pour que le conteneur prenne sa taille réelle

  4. Ajoutez du code HTML global, définissez la hauteur du corps à 100% pour voir la couleur partout

  5. Supprimer le remplacement du corps dans Apple

donc, appComponent.ts:

html, body {
  height: 100%;
}

appComponent.html:

/*Sample "global" CSS, that affects something outside the current component.*/
::ng-deep {
  @media print {
    @page {
      margin: 0;
    }
  }
}

appComponent.scss

.red {
  background-color: red;
}

.container {
  height: 100%;
}

apple.component.scss (supprimer le corps)

<div [ngClass]="{'red':isApple}" class="container">
    <p>
        There are two components: Apple and Banana. Switching between them will show
        the problem.
    </p>

    <router-outlet></router-outlet>
</div>

styles.scss (global)

  isApple: Boolean;
  constructor(router: Router) {
    router.events.subscribe(v => {
      if (v instanceof NavigationEnd) {
        this.isApple = v.url === "/apple";
      }
    });
  }

Vous pouvez voir tout cela sur ce lien Stackblitz


2 commentaires

.... Tout l'objectif est de mettre du CSS sur le corps. (Pour comprendre pourquoi nous pourrions avoir besoin de CSS global, le scénario du monde réel qui a inspiré ma question cachait les <header> et <footer> sur une page particulière lors de l'impression ... sans changer le code de app.component.html , puisque nous avons BEAUCOUP de pages et qu'un seul composant a cette exigence.)


Quoi qu'il en soit, votre code ne résout rien en ce qui concerne @media print. Nous avons toujours exactement le même problème qu'avant.



1
votes

Angular effectue un rendu côté client, ce qui est une mauvaise nouvelle, car vous n'avez pas de pages séparées. Vous avez cependant plusieurs solutions possibles:

1. Page séparée

Vous pouvez créer une autre page avec ou sans Angular, qui comprend le CSS dont vous avez besoin et charger cette page. Dans l'approche la plus simpliste pour y parvenir, l'autre page aurait une URL différente. Si avoir une URL différente ne vous convient pas, vous pouvez masquer le contenu de votre page et afficher l'autre page dans un iframe . Ce serait certes une solution pirate, mais c'est une solution.

2. Rendu CSS côté client

Au lieu de simplement charger le CSS, vous pourriez avoir un composant qui contrôlerait les règles CSS globales, correspondant au nom de votre vue. Vous auriez une valeur de modèle rendue à une propriété, comme:

body.custom-print {
    margin: 30px;
}

Et lorsque vous visitez la page où cela doit être activé, vous initialiserez simplement une propriété avec un élément HTML de style qui a été généré en fonction du modèle et ajouté à l'en- head . Une fois que vous quittez la vue donnée, votre composant détecte cet événement et remove() cet élément. Si vous choisissez cette solution, il serait sage de vous assurer que vous la soutenez de manière plus générale, de sorte que si certaines nouvelles vues auront leur CSS global personnalisé, elles seront alors faciles à intégrer dans votre projet à l'avenir. .

3. cours de corps

Vous pouvez ajouter / supprimer une custom-print ou n'importe quelle classe dans le body chaque fois que le style doit être modifié. De cette façon, vous pouvez ajouter le CSS exactement une fois à votre HTML et modifier les règles en conséquence, comme:

`
@media print{
    @page{
        margin:0;
    }
    body{
        margin:30px;
    }
}
`

Ce serait une solution @page , mais le problème dans votre cas est que vous avez également une règle @page et je ne sais pas comment vous pourriez la rendre dépendante des classes de corps ou de certains autres attributs HTML. Je ferais pas mal d'expériences à ce sujet si j'étais vous.

4. Mise en scène Iframe

Vous pourriez éviter d'avoir ce CSS dans votre page principale, mais auriez un iframe caché où vous auriez le CSS et copieriez simplement le contenu dans le CSS et une fois qu'il est chargé, imprimez-le.


1 commentaires

1 et 4 sont fondamentalement les mêmes, "Mettre le contenu dans une iframe" ... Ce qui est assez drastique, mais techniquement fonctionnera. # 3 J'avais déjà écrit dans le cadre de la question et je l'avais rejetée pour la même raison que vous. # 2 semble être la seule solution raisonnable, et nous pouvons probablement écrire une sorte de service pour le faire aussi. (Plutôt que de mettre le CSS dans un fichier HTML ou CSS, mettez simplement le CSS dans votre fichier .ts , et utilisez JS pour l'ajouter sur ngInit et le supprimer sur ngDestroy.) C'est une idée intéressante.



2
votes

Résolu! Via DomSanitizer.bypassSecurityTrustHtml

Voici un StackBlitz .

Tout d'abord, créez un nouveau composant pour gérer le travail:

<app-local-css [style]="'body{background:green !important;}'"></app-local-css>
// OR
<app-local-css [scriptURL]="'/path/to/file.css'"></app-local-css>

Et puis utilisez-le comme ceci:

mySample.component.html:

component.ts: (This is all we need. We don't need an HTML or style.css file.)
//Inside  your local component, place this HTML 
//<app-local-css [style]="'body{background:green !important;}'"></app-local-css>
// OR
//<app-local-css [scriptURL]="'/path/to/file.css'"></app-local-css>

@Component({
  selector: "app-local-css",
  template: '<span style="display:none" [innerHTML]="this.safeString"></span>'
})
export class LocalCSSComponent implements OnInit {
  constructor(protected sanitizer: DomSanitizer) {}
  @Input() scriptURL?: string;
  @Input() style?: string;

  safeString: SafeHtml;
  ngOnInit() {
    if (this.scriptURL) {
      let string = '<link rel="stylesheet" type="text/css" href="' + this.scriptURL + '">';
      this.safeString = this.sanitizer.bypassSecurityTrustHtml(string);
    } else if (this.style) {
      let string = '<style type="text/css">' + this.style + "</style>";
      this.safeString = this.sanitizer.bypassSecurityTrustHtml(string);
    }
  }
}

Cela fonctionne parce que le CSS se trouve à l'intérieur du HTML, et par conséquent, lorsque le composant sera détruit, ce sera aussi le cas. (Angular ne tentera pas de modifier cela à cause de bypassSecurityTrustHtml )


0 commentaires